transactd 2.4.5 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. checksums.yaml +4 -4
  2. data/CMakeLists.txt +1 -1
  3. data/README-JA.md +52 -529
  4. data/README.md +52 -523
  5. data/bin/common/tdclc_32_3_0.dll +0 -0
  6. data/bin/common/tdclc_64_3_0.dll +0 -0
  7. data/build/common/system.cmake +2 -1
  8. data/build/common/transactd_cl_common.cmake +3 -6
  9. data/build/swig/ruby/ruby.swg +85 -28
  10. data/build/swig/ruby/tdclrb_wrap.cpp +3195 -1578
  11. data/build/swig/tdcl.i +161 -5
  12. data/build/tdclc/CMakeLists.txt +1 -0
  13. data/build/tdclc/tdclc.cbproj +7 -1
  14. data/build/tdclc/tdclc.rc +4 -4
  15. data/build/tdclcpp/tdclcpp.rc +4 -4
  16. data/build/tdclcpp/tdclcpp_bc.cbproj +2 -5
  17. data/build/tdclrb/tdclrb.rc +4 -4
  18. data/source/bzs/db/blobStructs.h +1 -1
  19. data/source/bzs/db/engine/mysql/database.cpp +199 -74
  20. data/source/bzs/db/engine/mysql/database.h +47 -18
  21. data/source/bzs/db/engine/mysql/dbManager.cpp +1 -0
  22. data/source/bzs/db/engine/mysql/mysqlInternal.h +32 -8
  23. data/source/bzs/db/protocol/tdap/btrDate.cpp +110 -75
  24. data/source/bzs/db/protocol/tdap/btrDate.h +46 -21
  25. data/source/bzs/db/protocol/tdap/client/activeTable.cpp +18 -18
  26. data/source/bzs/db/protocol/tdap/client/activeTable.h +25 -25
  27. data/source/bzs/db/protocol/tdap/client/activeTableImple.h +10 -4
  28. data/source/bzs/db/protocol/tdap/client/client.cpp +6 -5
  29. data/source/bzs/db/protocol/tdap/client/client.h +82 -15
  30. data/source/bzs/db/protocol/tdap/client/database.cpp +531 -142
  31. data/source/bzs/db/protocol/tdap/client/database.h +19 -6
  32. data/source/bzs/db/protocol/tdap/client/dbDef.cpp +461 -408
  33. data/source/bzs/db/protocol/tdap/client/dbDef.h +11 -17
  34. data/source/bzs/db/protocol/tdap/client/dllmain.cpp +61 -13
  35. data/source/bzs/db/protocol/tdap/client/field.cpp +1592 -1398
  36. data/source/bzs/db/protocol/tdap/client/field.h +110 -121
  37. data/source/bzs/db/protocol/tdap/client/fields.h +40 -10
  38. data/source/bzs/db/protocol/tdap/client/filter.h +69 -55
  39. data/source/bzs/db/protocol/tdap/client/groupQuery.cpp +296 -164
  40. data/source/bzs/db/protocol/tdap/client/groupQuery.h +77 -25
  41. data/source/bzs/db/protocol/tdap/client/memRecord.cpp +31 -13
  42. data/source/bzs/db/protocol/tdap/client/memRecord.h +31 -21
  43. data/source/bzs/db/protocol/tdap/client/nsDatabase.cpp +1 -1
  44. data/source/bzs/db/protocol/tdap/client/nsDatabase.h +4 -1
  45. data/source/bzs/db/protocol/tdap/client/nsTable.cpp +69 -24
  46. data/source/bzs/db/protocol/tdap/client/nsTable.h +3 -1
  47. data/source/bzs/db/protocol/tdap/client/recordset.cpp +1 -0
  48. data/source/bzs/db/protocol/tdap/client/recordsetImple.h +46 -27
  49. data/source/bzs/db/protocol/tdap/client/request.h +2 -1
  50. data/source/bzs/db/protocol/tdap/client/serializer.cpp +44 -9
  51. data/source/bzs/db/protocol/tdap/client/serializer.h +1 -1
  52. data/source/bzs/db/protocol/tdap/client/sqlBuilder.cpp +182 -76
  53. data/source/bzs/db/protocol/tdap/client/sqlBuilder.h +23 -12
  54. data/source/bzs/db/protocol/tdap/client/stringConverter.h +8 -10
  55. data/source/bzs/db/protocol/tdap/client/table.cpp +172 -93
  56. data/source/bzs/db/protocol/tdap/client/table.h +112 -37
  57. data/source/bzs/db/protocol/tdap/client/trdboostapi.h +17 -0
  58. data/source/bzs/db/protocol/tdap/client/trdboostapiInternal.h +0 -1
  59. data/source/bzs/db/protocol/tdap/client/trdclcppautolink.h +0 -2
  60. data/source/bzs/db/protocol/tdap/client/trdormapi.h +1 -1
  61. data/source/bzs/db/protocol/tdap/fieldComp.h +698 -14
  62. data/source/bzs/db/protocol/tdap/myDateTime.cpp +723 -307
  63. data/source/bzs/db/protocol/tdap/myDateTime.h +294 -0
  64. data/source/bzs/db/protocol/tdap/mysql/databaseSchema.cpp +164 -54
  65. data/source/bzs/db/protocol/tdap/mysql/databaseSchema.h +6 -3
  66. data/source/bzs/db/protocol/tdap/mysql/recordsetReader.h +133 -550
  67. data/source/bzs/db/protocol/tdap/mysql/request.h +6 -5
  68. data/source/bzs/db/protocol/tdap/mysql/tdapCommandExecuter.cpp +217 -82
  69. data/source/bzs/db/protocol/tdap/mysql/tdapCommandExecuter.h +1 -1
  70. data/source/bzs/db/protocol/tdap/tdapRequest.h +4 -9
  71. data/source/bzs/db/protocol/tdap/tdapSchema.cpp +808 -17
  72. data/source/bzs/db/protocol/tdap/tdapSchema.h +656 -164
  73. data/source/bzs/db/protocol/tdap/tdapcapi.h +130 -28
  74. data/source/bzs/db/protocol/tdap/uri.h +40 -32
  75. data/source/bzs/db/transactd/connManager.cpp +1 -1
  76. data/source/bzs/db/transactd/transactd.cpp +7 -0
  77. data/source/bzs/env/compiler.h +107 -94
  78. data/source/bzs/env/crosscompile.cpp +24 -12
  79. data/source/bzs/env/crosscompile.h +75 -6
  80. data/source/bzs/env/mbcswchrLinux.cpp +2 -2
  81. data/source/bzs/env/tcharMinGW.h +4 -0
  82. data/source/bzs/example/changeSchema.cpp +22 -17
  83. data/source/bzs/example/queryData.cpp +4 -0
  84. data/source/bzs/netsvc/client/iconnection.h +3 -1
  85. data/source/bzs/netsvc/client/tcpClient.h +10 -3
  86. data/source/bzs/rtl/stringBuffers.cpp +7 -0
  87. data/source/bzs/test/tdclatl/bench_query_atl.js +6 -0
  88. data/source/bzs/test/tdclatl/bench_tdclatl.js +8 -1
  89. data/source/bzs/test/tdclatl/test_query_atl.js +22 -2
  90. data/source/bzs/test/tdclatl/test_v3.js +1017 -0
  91. data/source/bzs/test/tdclphp/transactd_Test.php +55 -21
  92. data/source/bzs/test/tdclphp/transactd_datetime_Test.php +0 -5
  93. data/source/bzs/test/tdclphp/transactd_pool_Test.php +2 -0
  94. data/source/bzs/test/tdclphp/transactd_v3_Test.php +743 -0
  95. data/source/bzs/test/tdclrb/transactd_datetime_spec.rb +0 -5
  96. data/source/bzs/test/tdclrb/transactd_pool_spec.rb +2 -0
  97. data/source/bzs/test/tdclrb/transactd_spec.rb +39 -16
  98. data/source/bzs/test/tdclrb/transactd_v3_spec.rb +748 -0
  99. data/source/bzs/test/transactdBench/transactdBench.cpp +55 -58
  100. data/source/bzs/test/transactdBench/transactdBench2.cpp +1 -3
  101. data/source/bzs/test/trdclengn/testField.h +3305 -0
  102. data/source/bzs/test/trdclengn/test_tdclcpp_v3.cpp +1050 -0
  103. data/source/bzs/test/trdclengn/test_trdclengn.cpp +112 -190
  104. data/source/bzs/test/trdclengn/testbase.h +137 -0
  105. data/source/global/ormsrcgen/srcgen.cpp +23 -12
  106. data/source/global/ormsrcgen/template/ormDataClass_template.h +2 -0
  107. data/source/global/querystmts/querystmts.cpp +2 -3
  108. data/source/global/tdclatl/Bitset.cpp +38 -0
  109. data/source/global/tdclatl/Bitset.h +63 -0
  110. data/source/global/tdclatl/Database.cpp +59 -18
  111. data/source/global/tdclatl/Database.h +7 -4
  112. data/source/global/tdclatl/DbDef.cpp +6 -6
  113. data/source/global/tdclatl/DbDef.h +2 -1
  114. data/source/global/tdclatl/Field.cpp +112 -0
  115. data/source/global/tdclatl/Field.h +19 -5
  116. data/source/global/tdclatl/FieldDef.cpp +137 -16
  117. data/source/global/tdclatl/FieldDef.h +18 -2
  118. data/source/global/tdclatl/FieldDefs.cpp +54 -1
  119. data/source/global/tdclatl/FieldDefs.h +3 -0
  120. data/source/global/tdclatl/GroupQuery.cpp +8 -8
  121. data/source/global/tdclatl/QueryBase.cpp +65 -0
  122. data/source/global/tdclatl/QueryBase.h +10 -0
  123. data/source/global/tdclatl/Record.cpp +33 -2
  124. data/source/global/tdclatl/Record.h +3 -1
  125. data/source/global/tdclatl/RecordsetQuery.cpp +42 -0
  126. data/source/global/tdclatl/RecordsetQuery.h +8 -0
  127. data/source/global/tdclatl/Table.cpp +127 -3
  128. data/source/global/tdclatl/Table.h +10 -1
  129. data/source/global/tdclatl/TableDef.cpp +41 -8
  130. data/source/global/tdclatl/TableDef.h +7 -2
  131. data/source/global/tdclatl/activeTable.cpp +40 -71
  132. data/source/global/tdclatl/resource.h +0 -0
  133. data/source/global/tdclatl/tdclatl.idl +222 -28
  134. data/source/linux/tchar.h +100 -96
  135. data/transactd.gemspec +2 -2
  136. metadata +13 -11
  137. data/BUILD_UNIX-JA.md +0 -161
  138. data/BUILD_WIN-JA.md +0 -326
  139. data/README_ORMSRCGEN-JA.md +0 -115
  140. data/README_ORMSRCGEN.md +0 -118
  141. data/RELEASE_NOTE-JA.md +0 -356
  142. data/RELEASE_NOTE.md +0 -360
  143. data/bin/common/tdclc_32_2_4.dll +0 -0
  144. data/bin/common/tdclc_64_2_4.dll +0 -0
  145. data/source/bzs/test/trdclengn/test_blob.cpp +0 -375
@@ -20,6 +20,7 @@
20
20
  =================================================================*/
21
21
  #include "trdormapi.h"
22
22
  #include "groupQuery.h"
23
+ #include <bzs/rtl/stringBuffers.h>
23
24
  #ifdef _DEBUG
24
25
  #include <iostream>
25
26
  #include <iomanip>
@@ -57,14 +58,14 @@ class dumpRecordset
57
58
 
58
59
  for (size_t col = 0; col < fds.size(); ++col)
59
60
  {
60
- m_widths[col] = std::max(_tcslen(fds[col].name()), m_widths[col]);
61
- m_ailgns[col] = fds[col].isStringType() ? std::ios::left : std::ios::right;
61
+ m_widths[col] = std::max(_tcslen(fds[(short)col].name()), (size_t)4);
62
+ m_ailgns[col] = (fds[(short)col].isStringType() ? std::ios::left : std::ios::right);
62
63
  }
63
64
  for(size_t i = 0; i < rs.size(); ++i)
64
65
  {
65
66
  row& rec = rs[i];
66
67
  for (size_t col = 0; col < fds.size(); ++col)
67
- m_widths[col] = std::max(_tcslen(rec[col].c_str()), m_widths[col]);
68
+ m_widths[col] = std::max(_tcslen(rec[(short)col].c_str()), m_widths[col]);
68
69
  }
69
70
  }
70
71
 
@@ -87,30 +88,39 @@ class dumpRecordset
87
88
  }
88
89
 
89
90
  const _TCHAR* value(const fielddef& fd) {return fd.name();}
90
- const _TCHAR* value(const field& fd) {return fd.c_str();}
91
+ const _TCHAR* value(const field& fd)
92
+ {
93
+ if (fd.isNull())
94
+ return _T("NULL");
95
+ return fd.c_str();
96
+ }
91
97
 
92
98
  template <class T>
93
99
  void printRecord(const T& coll)
94
100
  {
95
101
  std::tcout << _T("|");
96
102
  for (size_t col = 0; col < m_widths.size(); ++col)
97
- printValue(m_widths[col], m_ailgns[col], value(coll[col]));
103
+ printValue(m_widths[col], m_ailgns[col], value(coll[(short)col]));
98
104
  std::tcout << std::endl;
99
105
  }
100
106
  public:
101
107
  void operator()(RS& rs)
102
108
  {
103
- cacheWidthAndAlign(rs);
104
- std::_tstring line = makeLine();
105
- //header
106
- std::tcout << line;
107
- printRecord(*rs.fieldDefs());
108
- std::tcout << line;
109
-
110
- //field value
111
- for(size_t i = 0; i < rs.size(); ++i)
112
- printRecord(rs[i]);
113
- std::tcout << line;
109
+ if (rs.size())
110
+ {
111
+ cacheWidthAndAlign(rs);
112
+ std::_tstring line = makeLine();
113
+ //header
114
+ std::tcout << line;
115
+ printRecord(*rs.fieldDefs());
116
+ std::tcout << line;
117
+
118
+ //field value
119
+ for(size_t i = 0; i < rs.size(); ++i)
120
+ printRecord(rs[i]);
121
+ std::tcout << line;
122
+ }else
123
+ std::tcout << _T("Empty set ") << std::endl;
114
124
  }
115
125
  };
116
126
  #endif
@@ -163,7 +173,8 @@ public:
163
173
  inline unsigned char* ptr(size_t row, int stat);
164
174
  inline void setRowOffset(int v) { m_rowOffset = v; }
165
175
  inline void setJoinType(int v) { m_addType = v; }
166
- inline void setInvalidRecord(size_t row, bool v);
176
+ inline int joinType() const {return m_addType; };
177
+ inline void setInvalidMemblock(size_t row, bool v);
167
178
  inline void setCurFirstField(int v) { m_curFirstField = v; }
168
179
  inline void setJoinRowMap(const std::vector<std::vector<int> >* v)
169
180
  {
@@ -229,7 +240,7 @@ private:
229
240
  m_mra->setRowOffset(0);
230
241
  m_mra->setCurFirstField((int)m_fds->size());
231
242
  if (tb)
232
- m_fds->copyFrom(tb);
243
+ m_fds->addSelectedFields(tb);
233
244
  if (tb && (addtype == mra_nojoin))
234
245
  {
235
246
  const keydef& kd = tb->tableDef()->keyDefs[(int)tb->keyNum()];
@@ -407,11 +418,11 @@ public:
407
418
  std::vector<short> offsetIndex;
408
419
  for (int j = 0; j < (int)m_fds->size(); ++j)
409
420
  {
410
- if (m_fds->operator[](j).blobLenBytes())
421
+ if (blobLenBytes(m_fds->operator[](j)))
411
422
  {
412
423
  blobs.push_back((short)j);
413
424
  unsigned char* p = (unsigned char*)(*m_recordset[0])[j].ptr()
414
- + m_fds->operator[](j).blobLenBytes();
425
+ + blobLenBytes(m_fds->operator[](j));
415
426
  short index = (short)getMemBlockIndex(p);
416
427
  offsetIndex.push_back(index);
417
428
  }
@@ -422,7 +433,8 @@ public:
422
433
  dynamic_cast<memoryRecord*>(m_recordset[i]);
423
434
  memoryRecord* mr = recs + i;
424
435
  p->push_back(mr);
425
- mr->m_invalidRecord = row->m_invalidRecord;
436
+ mr->m_InvalidFlags = row->m_InvalidFlags;
437
+
426
438
  for (int j = 0; j < (int)row->memBlockSize(); ++j)
427
439
  {
428
440
  const autoMemory& mb = row->memBlock(j);
@@ -432,6 +444,7 @@ public:
432
444
  #pragma warn .8072
433
445
  autoMemory* a = amar + amindex;
434
446
  const boost::shared_ptr<autoMemory>& am = p->m_memblock[index];
447
+ // isInvalidRecord will be reset.
435
448
  mr->setRecordData(a, ptr, mb.size, am->endFieldIndex, mb.owner);
436
449
  ++amindex;
437
450
  }
@@ -640,7 +653,7 @@ public:
640
653
  return *this;
641
654
  }
642
655
 
643
- inline void appendField(const _TCHAR* name, int type, short len)
656
+ inline void appendField(const _TCHAR* name, int type, short len, uchar_td decimals=0)
644
657
  {
645
658
  assert(m_fds->size());
646
659
 
@@ -649,8 +662,9 @@ public:
649
662
  fd.len = len;
650
663
  fd.pos = 0;
651
664
  fd.type = type;
665
+ fd.decimals = decimals;
652
666
  fd.setName(name);
653
- if (fd.blobLenBytes())
667
+ if (blobLenBytes(fd))
654
668
  THROW_BZS_ERROR_WITH_MSG(_T("Can not append Blob or Text field."));
655
669
  m_fds->push_back(&fd);
656
670
  if (size())
@@ -673,6 +687,11 @@ public:
673
687
  return *this;
674
688
  }
675
689
 
690
+ inline void clearStringBuffer()
691
+ {
692
+ m_fds->strBufs()->clear();
693
+ }
694
+
676
695
  #ifdef _DEBUG
677
696
  void dump()
678
697
  {
@@ -705,19 +724,19 @@ inline unsigned char* multiRecordAlocatorImple::ptr(size_t row, int stat)
705
724
  int col = (stat == mra_current_block) ? m_curFirstField : 0;
706
725
  size_t rowNum = m_joinRowMap ? (*m_joinRowMap)[row + m_rowOffset][0]
707
726
  : row + m_rowOffset;
708
- return (*m_rs)[rowNum].ptr(col);
727
+ return (*m_rs)[rowNum].nullPtr(col);
709
728
  }
710
729
 
711
- inline void multiRecordAlocatorImple::setInvalidRecord(size_t row, bool v)
730
+ inline void multiRecordAlocatorImple::setInvalidMemblock(size_t row, bool v)
712
731
  {
713
732
  if (m_joinRowMap)
714
733
  {
715
734
  const std::vector<int>& map = (*m_joinRowMap)[row + m_rowOffset];
716
735
  for (int j = 0; j < (int)map.size(); ++j)
717
- (*m_rs)[map[j]].setInvalidRecord(v);
736
+ (*m_rs)[map[j]].setInvalidMemblock(v ? m_curFirstField : 0);
718
737
  }
719
738
  else
720
- (*m_rs)[row + m_rowOffset].setInvalidRecord(v);
739
+ (*m_rs)[row + m_rowOffset].setInvalidMemblock(v ? m_curFirstField : 0);
721
740
  }
722
741
 
723
742
  inline void multiRecordAlocatorImple::duplicateRow(int row, int count)
@@ -18,9 +18,10 @@
18
18
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19
19
  02111-1307, USA.
20
20
  ================================================================= */
21
-
21
+ #pragma warning(disable : 4005) //BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT redefine bug
22
22
  #include <bzs/db/protocol/tdap/tdapRequest.h>
23
23
  #include <bzs/netsvc/client/iconnection.h>
24
+ #pragma warning(default : 4005)
24
25
 
25
26
  #ifdef USE_DATA_COMPRESS
26
27
  #include <bzs/rtl/lzss.h>
@@ -66,7 +66,8 @@ BOOST_CLASS_EXPORT_GUID(bzs::db::protocol::tdap::client::reverseOrderStatement,
66
66
 
67
67
  BOOST_CLASS_VERSION(bzs::db::protocol::tdap::client::groupFuncBase, 1)
68
68
  BOOST_CLASS_VERSION(bzs::db::protocol::tdap::client::queryBase, 1)
69
-
69
+ BOOST_CLASS_VERSION(bzs::db::protocol::tdap::client::readStatement, 1)
70
+ BOOST_CLASS_VERSION(bzs::db::protocol::tdap::client::readHasMany, 1)
70
71
  namespace bzs
71
72
  {
72
73
  namespace db
@@ -178,11 +179,15 @@ void serialize(Archive& /*ar*/, reverseOrderStatement& q,
178
179
  }
179
180
 
180
181
  template <class Archive>
181
- void serialize(Archive& ar, readStatement& q, const unsigned int /*version*/)
182
+ void serialize(Archive& ar, readStatement& q, const unsigned int version)
182
183
  {
183
184
  boost::serialization::base_object<executable>(q);
184
- ar& boost::serialization::make_nvp(
185
- "keyFields", boost::serialization::base_object<fieldNames>(q));
185
+ if (version < 1)
186
+ ar& boost::serialization::make_nvp(
187
+ "keyFields", boost::serialization::base_object<fieldNames>(q));
188
+ else
189
+ ar& boost::serialization::make_nvp(
190
+ "keyValues", boost::serialization::base_object<fieldValues>(q));
186
191
  ar& boost::serialization::make_nvp(
187
192
  "query", boost::serialization::base_object<query>(q));
188
193
  ar& boost::serialization::make_nvp("params", *q.internalPtr());
@@ -191,7 +196,6 @@ void serialize(Archive& ar, readStatement& q, const unsigned int /*version*/)
191
196
  template <class Archive>
192
197
  void serialize(Archive& ar, readHasMany& q, const unsigned int /*version*/)
193
198
  {
194
-
195
199
  ar& boost::serialization::make_nvp(
196
200
  "readStatement", boost::serialization::base_object<readStatement>(q));
197
201
  ar& boost::serialization::make_nvp("params", *q.internalPtr());
@@ -286,6 +290,31 @@ void serialize(Archive& ar, fieldNames& q, const unsigned int /*version*/)
286
290
  }
287
291
  }
288
292
 
293
+ template <class Archive>
294
+ void serialize(Archive& ar, fieldValues& q, const unsigned int /*version*/)
295
+ {
296
+ int count = q.count();
297
+ ar& boost::serialization::make_nvp("count", count);
298
+ std::_tstring s;
299
+ bool isNull;
300
+ for (int i = 0; i < count; i++)
301
+ {
302
+ if (Archive::is_loading::value)
303
+ {
304
+ serialize_string(ar, "value", s);
305
+ ar& boost::serialization::make_nvp("isNull", isNull);
306
+ q.addValue(s.c_str(), isNull);
307
+ }
308
+ else
309
+ {
310
+ s = q.getValue(i);
311
+ serialize_string(ar, "value", s);
312
+ isNull = q.isNull(i);
313
+ ar& boost::serialization::make_nvp("isNull", isNull);
314
+ }
315
+ }
316
+ }
317
+
289
318
  template <class Archive>
290
319
  void serialize(Archive& ar, query& q, const unsigned int /*version*/)
291
320
  {
@@ -470,7 +499,10 @@ groupFuncBase& groupByStatement::addFunction(eFunc v,
470
499
  func = new client::sum(targetNames, resultName);
471
500
  break;
472
501
  case fcount:
473
- func = new client::count(resultName);
502
+ if (targetNames.count())
503
+ func = new client::count(targetNames, resultName);
504
+ else
505
+ func = new client::count(resultName);
474
506
  break;
475
507
  case favg:
476
508
  func = new client::avg(targetNames, resultName);
@@ -669,7 +701,7 @@ struct queryStatementImple
669
701
  std::_tstring database;
670
702
  std::_tstring table;
671
703
  int option;
672
- fieldNames* keyFields;
704
+ fieldValues* keyFields;
673
705
  client::query* query;
674
706
  readStatement::eReadType readType;
675
707
  short index;
@@ -707,6 +739,9 @@ struct queryStatementImple
707
739
  const _TCHAR* keys[8] = { NULL };
708
740
  for (int i = 0; i < keyFields->count(); ++i)
709
741
  keys[i] = parent->pv.replace(keyFields->getValue(i));
742
+ for (int i = 0; i < keyFields->count(); ++i)
743
+ if(keyFields->isNull(i))
744
+ keys[i] = NULL;
710
745
 
711
746
  client::query q;
712
747
  client::query* tq = replaceQueryParams(query, q, parent);
@@ -1279,12 +1314,12 @@ void readHasMany::execute(recordset& rs)
1279
1314
 
1280
1315
  for (int i = 0; i < (int)rs.size(); ++i)
1281
1316
  {
1282
- fieldNames::reset();
1317
+ fieldValues::reset();
1283
1318
  // setkey values
1284
1319
  for (int j = 0; j < (int)indexes.size(); ++j)
1285
1320
  {
1286
1321
  const _TCHAR* p = rs[i][indexes[j]].c_str();
1287
- addValue(p);
1322
+ addValue(p, rs[i][indexes[j]].isNull());
1288
1323
  if (j == 0)
1289
1324
  addLogic(getkeyValueColumn(j), _T("="), p);
1290
1325
  else
@@ -150,7 +150,7 @@ public:
150
150
  static reverseOrderStatement* create();
151
151
  };
152
152
 
153
- class DLLLIBSTMT readStatement : public fieldNames,
153
+ class DLLLIBSTMT readStatement : public fieldValues,
154
154
  public query,
155
155
  public executable
156
156
  {