transactd 3.3.0 → 3.4.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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/bin/common/{tdclc_32_3_3.dll → tdclc_32_3_4.dll} +0 -0
  3. data/bin/common/tdclc_64_3_4.dll +0 -0
  4. data/build/swig/ruby/tdclrb_wrap.cpp +66 -11
  5. data/build/swig/tdcl.i +0 -1
  6. data/build/tdclc/tdclc.cbproj +1 -1
  7. data/build/tdclc/tdclc.rc +4 -4
  8. data/build/tdclcpp/tdclcpp.rc +4 -4
  9. data/build/tdclcpp/tdclcpp_bc.cbproj +1 -1
  10. data/build/tdclrb/tdclrb.rc +4 -4
  11. data/source/bzs/db/engine/mysql/database.cpp +14 -5
  12. data/source/bzs/db/engine/mysql/database.h +2 -1
  13. data/source/bzs/db/engine/mysql/mysqlInternal.h +3 -0
  14. data/source/bzs/db/engine/mysql/mysqlProtocol.cpp +103 -72
  15. data/source/bzs/db/engine/mysql/mysqlProtocol.h +0 -2
  16. data/source/bzs/db/protocol/tdap/client/connMgr.cpp +51 -4
  17. data/source/bzs/db/protocol/tdap/client/connMgr.h +2 -1
  18. data/source/bzs/db/protocol/tdap/client/database.cpp +30 -13
  19. data/source/bzs/db/protocol/tdap/client/database.h +2 -0
  20. data/source/bzs/db/protocol/tdap/client/errorMessage.cpp +13 -3
  21. data/source/bzs/db/protocol/tdap/client/errorMessage_ja.cpp +13 -3
  22. data/source/bzs/db/protocol/tdap/client/field.cpp +2 -1
  23. data/source/bzs/db/protocol/tdap/client/field.h +4 -2
  24. data/source/bzs/db/protocol/tdap/client/filter.h +2 -1
  25. data/source/bzs/db/protocol/tdap/client/nsDatabase.cpp +65 -1
  26. data/source/bzs/db/protocol/tdap/client/nsDatabase.h +14 -2
  27. data/source/bzs/db/protocol/tdap/client/table.cpp +72 -21
  28. data/source/bzs/db/protocol/tdap/client/trdboostapi.h +10 -1
  29. data/source/bzs/db/protocol/tdap/fieldComp.h +175 -43
  30. data/source/bzs/db/protocol/tdap/myDateTime.cpp +8 -4
  31. data/source/bzs/db/protocol/tdap/myDateTime.h +4 -4
  32. data/source/bzs/db/protocol/tdap/mysql/tdapCommandExecuter.cpp +2 -2
  33. data/source/bzs/db/protocol/tdap/tdapSchema.h +1 -1
  34. data/source/bzs/db/protocol/tdap/tdapcapi.h +7 -5
  35. data/source/bzs/db/protocol/tdap/uri.h +1 -1
  36. data/source/bzs/db/transactd/connectionRecord.h +29 -14
  37. data/source/bzs/netsvc/client/tcpClient.cpp +4 -3
  38. data/source/bzs/netsvc/client/tcpClient.h +2 -2
  39. data/source/bzs/netsvc/server/serverPipe.cpp +2 -8
  40. data/source/bzs/test/tdclatl/test_v3.js +7 -4
  41. data/source/bzs/test/tdclphp/transactd_v3_Test.php +7 -4
  42. data/source/bzs/test/tdclrb/transactd_v3_spec.rb +5 -4
  43. data/source/bzs/test/trdclengn/testField.h +7 -0
  44. data/source/global/tdclatl/ConnMgr.cpp +2 -1
  45. data/source/global/tdclatl/Database.cpp +10 -0
  46. data/source/global/tdclatl/Database.h +1 -1
  47. data/source/global/tdclatl/tdclatl.idl +3 -1
  48. metadata +4 -4
  49. data/bin/common/tdclc_64_3_3.dll +0 -0
@@ -61,8 +61,6 @@ public:
61
61
  ~safe_commit_lock();
62
62
  };
63
63
 
64
- short getBinlogPos(THD* thd, binlogPos* pos, THD* tmpThd);
65
- int getSlaveStatus(THD* thd, bzs::db::transactd::connection::records& recs);
66
64
  int execSql(THD* thd, const char* sql);
67
65
  void readDbList(THD* thd, bzs::db::transactd::connection::records& recs);
68
66
  bool setGrant(THD* thd, const char* host, const char* user, const char* db);
@@ -109,6 +109,42 @@ static const _TCHAR* SLAVE_STATUS_NAME[SLAVE_STATUS_DEFAULT_SIZE] =
109
109
  _T("Master_Server_Id" ),
110
110
  };
111
111
 
112
+ static const _TCHAR* SLAVE_STATUS_NAME_EX[SLAVE_STATUS_EX_SIZE] =
113
+ {
114
+ _T("Master_UUID"),
115
+ _T("Master_Info_File"),
116
+ _T("SQL_Delay"),
117
+ _T("SQL_Remaining_Delay"),
118
+ _T("Slave_SQL_Running_State"),
119
+ _T("Master_Retry_Count"),
120
+ _T("Master_Bind"),
121
+ _T("Last_IO_Error_Timestamp"),
122
+ _T("Last_SQL_Error_Timestamp"),
123
+ _T("Master_SSL_Crl"),
124
+ _T("Master_SSL_Crlpath"),
125
+ _T("Retrieved_Gtid_Set"),
126
+ _T("Executed_Gtid_Set"),
127
+ _T("Auto_Position"),
128
+ _T("Replicate_Rewrite_DB"),
129
+ _T("Channel_Name"),
130
+ };
131
+
132
+ static const _TCHAR* SLAVE_STATUS_NAME_EX_MA[SLAVE_STATUS_EX_MA_SIZE] =
133
+ {
134
+ _T("Master_SSL_Crl"),
135
+ _T("Master_SSL_Crlpath"),
136
+ _T("Using_Gtid"),
137
+ _T("Gtid_IO_Pos"),
138
+ _T("Replicate_Do_Domain_Ids"),
139
+ _T("Replicate_Ignore_Domain_Ids"),
140
+ _T("Parallel_Mode"),
141
+ _T("Retried_transactions"),
142
+ _T("Max_relay_log_size"),
143
+ _T("Executed_log_entries"),
144
+ _T("Slave_received_heartbeats"),
145
+ _T("Slave_heartbeat_period"),
146
+ _T("Gtid_Slave_Pos"),
147
+ };
112
148
 
113
149
  class stringBuffer
114
150
  {
@@ -245,6 +281,7 @@ bool connMgr::connect(const _TCHAR* uri)
245
281
  btrVersions vs;
246
282
  m_db->getBtrVersion(&vs);
247
283
  m_pluginVer = vs.versions[VER_IDX_PLUGIN];
284
+ m_serverVer = vs.versions[VER_IDX_DB_SERVER];
248
285
  }
249
286
  return ret;
250
287
  }
@@ -358,9 +395,6 @@ const connMgr::records& connMgr::slaveStatus()
358
395
  m_keynum = TD_STSTCS_SLAVE_STATUS;
359
396
  allocBuffer();
360
397
  getRecords();
361
- if (m_records.size() > SLAVE_STATUS_DEFAULT_SIZE)
362
- m_records.resize(SLAVE_STATUS_DEFAULT_SIZE);
363
-
364
398
  // set blob pointers
365
399
  setBlobFieldPointer(getBlobHeader());
366
400
  return m_records;
@@ -460,13 +494,26 @@ const _TCHAR* connMgr::statusvarName(uint_td index)
460
494
  return _T("");
461
495
  }
462
496
 
463
- const _TCHAR* connMgr::slaveStatusName(uint_td index)
497
+ const _TCHAR* slaveStatusName1(uint_td index)
464
498
  {
465
499
  if (index < SLAVE_STATUS_DEFAULT_SIZE)
466
500
  return SLAVE_STATUS_NAME[index];
467
501
  return _T("");
468
502
  }
469
503
 
504
+ const _TCHAR* connMgr::slaveStatusName(uint_td index) const
505
+ {
506
+ bool mariadb = m_serverVer.isMariaDB();
507
+ if (index < SLAVE_STATUS_DEFAULT_SIZE)
508
+ return slaveStatusName1(index);
509
+ index -= SLAVE_STATUS_DEFAULT_SIZE;
510
+ if(mariadb && (index < SLAVE_STATUS_EX_MA_SIZE))
511
+ return SLAVE_STATUS_NAME_EX_MA[index];
512
+ else if(!mariadb && (index < SLAVE_STATUS_EX_SIZE))
513
+ return SLAVE_STATUS_NAME_EX[index];
514
+ return _T("");
515
+ }
516
+
470
517
  } // namespace client
471
518
  } // namespace tdap
472
519
  } // namespace protocol
@@ -73,6 +73,7 @@ private:
73
73
  database* m_db;
74
74
  std::_tstring m_uri;
75
75
  btrVersion m_pluginVer;
76
+ btrVersion m_serverVer;
76
77
  void allocBuffer();
77
78
  void writeRecordData(){};
78
79
  void onReadAfter(){};
@@ -103,12 +104,12 @@ public:
103
104
  void postDisconnectAll();
104
105
  short_td stat();
105
106
  database* db() const;
107
+ const _TCHAR* slaveStatusName(uint_td index) const;
106
108
  using nstable::tdapErr;
107
109
  using nstable::release;
108
110
  static void removeSystemDb(records& recs);
109
111
  static const _TCHAR* sysvarName(uint_td index);
110
112
  static const _TCHAR* statusvarName(uint_td index);
111
- static const _TCHAR* slaveStatusName(uint_td index);
112
113
  static connMgr* create(database* db);
113
114
  };
114
115
 
@@ -1136,8 +1136,6 @@ struct fieldChnageInfo
1136
1136
  bool changed;
1137
1137
  };
1138
1138
 
1139
-
1140
-
1141
1139
  void makeChangeInfo(const tabledef* ddef, const tabledef* sdef,
1142
1140
  fieldChnageInfo* fci, bool& hasBlob)
1143
1141
  {
@@ -1235,32 +1233,51 @@ inline int moveVaileRecord(table* src)
1235
1233
  return 0;
1236
1234
  }
1237
1235
 
1236
+ #define MOVE_TYPE_KEY 0
1237
+ #define MOVE_TYPE_NONKEY -1
1238
+ #define MOVE_TYPE_MULTI -2
1239
+
1238
1240
  inline void moveNextRecord(table* src, short keyNum)
1239
1241
  {
1240
-
1241
- if (keyNum == -1)
1242
+ if (keyNum >= MOVE_TYPE_KEY)
1243
+ src->seekNext();
1244
+ else if (keyNum == MOVE_TYPE_NONKEY)
1242
1245
  src->stepNext();
1243
- else if (keyNum == -2)
1244
- src->findNext();
1245
1246
  else
1246
- src->seekNext();
1247
+ src->findNext();
1248
+ }
1249
+
1250
+ inline char_td findUniqueKeynum(table* src)
1251
+ {
1252
+ const tabledef* td = src->tableDef();
1253
+ if (td->parentKeyNum != 0xff) return td->parentKeyNum;
1254
+ for (int i=0;i<td->keyCount;++i)
1255
+ {
1256
+ const keydef* kd = &td->keyDefs[i];
1257
+ if (kd->segments[0].flags.kf_duplicatable == false)
1258
+ return i;
1259
+ }
1260
+ return -1;
1247
1261
  }
1248
1262
 
1249
1263
  inline void moveFirstRecord(table* src, short keyNum)
1250
1264
  {
1251
- if (keyNum == -1)
1265
+ if (keyNum >= MOVE_TYPE_KEY)
1266
+ {
1267
+ src->setKeyNum((char_td)keyNum);
1268
+ src->seekFirst();
1269
+ }
1270
+ else if (keyNum == MOVE_TYPE_NONKEY)
1252
1271
  src->stepFirst();
1253
- else if (keyNum == -2)
1272
+ else
1254
1273
  {
1255
- src->setKeyNum(0);
1256
1274
  query q;
1257
1275
  q.all().bookmarkAlso(false).reject(0)
1258
- .limit(src->isUseTransactd() ? 100 : 20);
1276
+ .limit(src->isUseTransactd() ? 500 : 20);
1259
1277
  src->setQuery(&q);
1278
+ src->setKeyNum(findUniqueKeynum(src));
1260
1279
  src->findFirst();
1261
1280
  }
1262
- else
1263
- src->seekFirst();
1264
1281
  }
1265
1282
 
1266
1283
  /* Copy from src to dest table.
@@ -136,6 +136,8 @@ public:
136
136
  void setAutoSchemaUseNullkey(bool v);
137
137
  database* createAssociate();
138
138
  virtual int defaultAutoIncSpace() const { return 0; };
139
+ inline bool execSql(const char* utf8Sql){return createTable(utf8Sql);}
140
+
139
141
  static database* create();
140
142
  /* For C++ direct only. don't use by wrapper class for COM or SWIG
141
143
  This method is ignore refarence count of nsdatabse.
@@ -163,11 +163,21 @@ _TCHAR* getErrorMessageLocale(int errorCode, _TCHAR* buf, size_t size)
163
163
  p = _T("Cannot create databse. Please check the database exists ")
164
164
  _T("already.");
165
165
  break;
166
+ case STATUS_SQL_PARSE_ERROR:
167
+ p = _T("Sql perse error.");
168
+ break;
166
169
  default:
170
+ {
171
+ const _TCHAR* s=_T("");
172
+ if (errorCode > MYSQL_ERROR_OFFSET)
173
+ {
174
+ s = _T(" of mysql error codes");
175
+ errorCode -= MYSQL_ERROR_OFFSET;
176
+ }
167
177
  _stprintf_s(buf, size, _T("The error occurred by database operation. ")
168
- _T("\nThe error code is %d.\nProcessing is ")
169
- _T("stopped."),
170
- errorCode);
178
+ _T("\nThe error code is %d%s.\nProcessing is ")
179
+ _T("stopped."), errorCode, s);
180
+ }
171
181
  }
172
182
  if (p)
173
183
  {
@@ -169,11 +169,21 @@ PACKAGE _TCHAR* getErrorMessageLocale(int errorCode, _TCHAR* buf, size_t size)
169
169
  p = _T("データベースの作成に失敗しました。既にデータベースが存在してい")
170
170
  _T("ないか確認してください。");
171
171
  break;
172
+ case STATUS_SQL_PARSE_ERROR:
173
+ p = _T("Sql perse error.");
174
+ break;
172
175
  default:
176
+ {
177
+ const _TCHAR* s=_T("");
178
+ if (errorCode > MYSQL_ERROR_OFFSET)
179
+ {
180
+ s = _T("MySqlのエラー番号");
181
+ errorCode -= MYSQL_ERROR_OFFSET;
182
+ }
173
183
  _stprintf_s(buf, 256, _T("データベースオペレーションでエラーが発生しま")
174
- _T("した。\r\nエラー番号は %d \r\n ")
175
- _T("処理を中止します。"),
176
- errorCode);
184
+ _T("した。\r\nエラー番号は%s %d \r\n処理を中止します。"),
185
+ s ,errorCode);
186
+ }
177
187
  }
178
188
  if (p)
179
189
  {
@@ -2227,7 +2227,8 @@ int field::comp(const field& r, char log) const
2227
2227
  int ret = nullComp(r, log & 0xf);
2228
2228
  if (ret < 2)
2229
2229
  return ret;
2230
- comp1Func f = getCompFunc(m_fd->type, m_fd->len, log, m_fd->varLenBytes() + m_fd->blobLenBytes());
2230
+ comp1Func f = getCompFunc(m_fd->type, m_fd->len, log | CMPLOGICAL_FIELD,
2231
+ m_fd->varLenBytes() + m_fd->blobLenBytes());
2231
2232
  return f((const char*)ptr(), (const char*)r.ptr(), r.len());
2232
2233
  }
2233
2234
 
@@ -239,9 +239,11 @@ public:
239
239
 
240
240
  void* ptr() const;
241
241
 
242
- unsigned char type() const { return m_fd->type; }
242
+ inline const fielddef* def() const {return m_fd;}
243
243
 
244
- unsigned short len() const { return m_fd->len; }
244
+ inline unsigned char type() const { return m_fd->type; }
245
+
246
+ inline unsigned short len() const { return m_fd->len; }
245
247
 
246
248
  inline const _TCHAR* c_str() const { return getFVstr(); }
247
249
 
@@ -1336,7 +1336,8 @@ public:
1336
1336
  bool checkFindDirection(ushort_td op)
1337
1337
  {
1338
1338
  bool ret;
1339
- if ((op == TD_KEY_LE_PREV_MULTI) || (op == TD_KEY_PREV_MULTI))
1339
+ if ((op == TD_KEY_LE_PREV_MULTI) || (op == TD_KEY_PREV_MULTI)||
1340
+ (op == TD_POS_PREV_MULTI))
1340
1341
  ret = (direction() == table::findBackForword);
1341
1342
  else
1342
1343
  ret = (direction() == table::findForword);
@@ -23,6 +23,7 @@
23
23
  #include <sys/stat.h>
24
24
  #include <stdio.h>
25
25
  #include <boost/thread/mutex.hpp>
26
+ #include <boost/shared_ptr.hpp>
26
27
  #include <bzs/db/protocol/tdap/uri.h>
27
28
 
28
29
  #ifdef LINUX
@@ -139,6 +140,49 @@ BTRCALLID_PTR getBtrvEntryPoint()
139
140
  return BTRCALLIDX;
140
141
  }
141
142
 
143
+ //------------------------------------------------------------------------------
144
+ struct bpimple
145
+ {
146
+ boost::shared_ptr<std::string> buf;
147
+ };
148
+
149
+ binlogPos::binlogPos() : m_impl(new bpimple), gtid(gtid_buf)
150
+ {
151
+ gtid_buf[0] = 0x00;
152
+ }
153
+
154
+ binlogPos::binlogPos(const binlogPos& r) : pos(r.pos), type(r.type),
155
+ m_impl(new bpimple(*r.m_impl))
156
+ {
157
+ strcpy_s(filename, BINLOGNAME_SIZE, r.filename);
158
+ strcpy_s(gtid_buf, GTID_SIZE, r.gtid_buf);
159
+ gtid = (r.gtid == r.gtid_buf) ? gtid_buf: r.gtid;
160
+ }
161
+
162
+ binlogPos::~binlogPos(){ delete m_impl;}
163
+
164
+ void binlogPos::setGtid(const char* p)
165
+ {
166
+ m_impl->buf.reset(new std::string(p));
167
+ gtid = m_impl->buf->c_str();
168
+ }
169
+
170
+ binlogPos& binlogPos::operator=(const binlogPos& r)
171
+ {
172
+ if (&r != this)
173
+ {
174
+ pos = r.pos;
175
+ type = r.type;
176
+ strcpy_s(filename, BINLOGNAME_SIZE, r.filename);
177
+ strcpy_s(gtid_buf, GTID_SIZE, r.gtid_buf);
178
+ gtid = (r.gtid == r.gtid_buf) ? gtid_buf: r.gtid;
179
+ *m_impl = *r.m_impl;
180
+ }
181
+ return *this;
182
+ }
183
+
184
+ //------------------------------------------------------------------------------
185
+
142
186
  struct nsdbimpl
143
187
  {
144
188
  int refCount;
@@ -634,7 +678,7 @@ void nsdatabase::beginSnapshot(short bias, binlogPos* bpos)
634
678
 
635
679
  if (m_nsimpl->snapShotCount == 0)
636
680
  {
637
- uint_td datalen = (bias == CONSISTENT_READ_WITH_BINLOG_POS) ? sizeof(binlogPos) : 0;
681
+ uint_td datalen = (bias == CONSISTENT_READ_WITH_BINLOG_POS) ? BINLOGPOS_SIZE : 0;
638
682
  m_stat = m_btrcallid(TD_BEGIN_SHAPSHOT + bias, NULL, bpos, &datalen, NULL, 0, 0,
639
683
  m_nsimpl->cidPtr);
640
684
  #ifdef TEST_RECONNECT
@@ -647,7 +691,27 @@ void nsdatabase::beginSnapshot(short bias, binlogPos* bpos)
647
691
  }
648
692
  #endif
649
693
  if (m_stat == 0)
694
+ {
695
+ if (bias == CONSISTENT_READ_WITH_BINLOG_POS)
696
+ {
697
+ if (bpos->type == REPL_POSTYPE_MARIA_GTID)
698
+ bpos->gtid = bpos->gtid_buf;
699
+ else if(bpos->type == REPL_POSTYPE_GTID)
700
+ {
701
+ const blobHeader* hd;
702
+ short stat = m_btrcallid(TD_GET_BLOB_BUF, NULL, &hd, NULL, NULL, 0, 0,
703
+ m_nsimpl->cidPtr);
704
+ if (stat == 0)
705
+ {
706
+ assert(hd->rows);
707
+ const blobField* f = hd->nextField;
708
+ bpos->setGtid(f->data());
709
+ }else
710
+ bpos->type = REPL_POSTYPE_POS;
711
+ }
712
+ }
650
713
  m_nsimpl->snapShotCount++;
714
+ }
651
715
  }
652
716
  else
653
717
  m_nsimpl->snapShotCount++;
@@ -57,12 +57,24 @@ DLLLIB BTRCALLID_PTR getTrnsctdEntryPoint();
57
57
  pragma_pack1
58
58
  #define BINLOGNAME_SIZE 119
59
59
  #define GTID_SIZE 64
60
- struct binlogPos
60
+ #define BINLOGPOS_SIZE 192
61
+ struct DLLLIB binlogPos
61
62
  {
63
+ friend class nsdatabase;
62
64
  unsigned long long pos;
63
65
  char type;
64
66
  char filename[BINLOGNAME_SIZE];
65
- char gtid[GTID_SIZE];
67
+ private:
68
+ char gtid_buf[GTID_SIZE];
69
+ struct bpimple* m_impl;
70
+ void setGtid(const char* p);
71
+ public:
72
+ const char* gtid;
73
+ binlogPos();
74
+ binlogPos(const binlogPos& r);
75
+ ~binlogPos();
76
+ binlogPos& operator=(const binlogPos& r);
77
+
66
78
  };
67
79
 
68
80
 
@@ -832,6 +832,12 @@ bool table::isReadContinue(ushort_td& op)
832
832
  op = filter->isSeeksMode() ?
833
833
  TD_KEY_SEEK_MULTI : (filter->direction() == table::findForword) ?
834
834
  TD_KEY_NEXT_MULTI : TD_KEY_PREV_MULTI;
835
+
836
+ if (m_keynum < 0 && op == TD_KEY_NEXT_MULTI)
837
+ op = TD_POS_NEXT_MULTI;
838
+ else if (m_keynum < 0 && op == TD_KEY_PREV_MULTI)
839
+ op = TD_POS_PREV_MULTI;
840
+
835
841
  return true;
836
842
  }
837
843
  if (m_impl->mraPtr)
@@ -1123,49 +1129,94 @@ void table::find(eFindType type)
1123
1129
 
1124
1130
  void table::findFirst()
1125
1131
  {
1126
- seekFirst();
1127
- if (m_stat == 0)
1132
+ if (m_keynum >= 0)
1128
1133
  {
1129
- if (m_impl->filterPtr)
1134
+ seekFirst();
1135
+ if (m_stat == 0)
1136
+ {
1137
+ if (m_impl->filterPtr)
1138
+ {
1139
+ m_impl->filterPtr->setPosTypeNext(false);
1140
+ getRecords(TD_KEY_NEXT_MULTI);
1141
+ }
1142
+ }
1143
+ }else
1144
+ {
1145
+ stepFirst();
1146
+ if (m_stat == 0)
1130
1147
  {
1131
- m_impl->filterPtr->setPosTypeNext(false);
1132
- getRecords(TD_KEY_NEXT_MULTI);
1148
+ if (m_impl->filterPtr)
1149
+ {
1150
+ m_impl->filterPtr->setPosTypeNext(false);
1151
+ getRecords(TD_POS_NEXT_MULTI);
1152
+ }
1133
1153
  }
1134
1154
  }
1135
1155
  }
1136
1156
 
1137
1157
  void table::findLast()
1138
1158
  {
1139
- seekLast();
1140
- if (m_stat == 0)
1159
+ if (m_keynum >= 0)
1141
1160
  {
1142
- if (m_impl->filterPtr)
1161
+ seekLast();
1162
+ if (m_stat == 0)
1143
1163
  {
1144
- m_impl->filterPtr->setPosTypeNext(false);
1145
- getRecords(TD_KEY_PREV_MULTI);
1164
+ if (m_impl->filterPtr)
1165
+ {
1166
+ m_impl->filterPtr->setPosTypeNext(false);
1167
+ getRecords(TD_KEY_PREV_MULTI);
1168
+ }
1169
+ }
1170
+ }else
1171
+ {
1172
+ stepLast();
1173
+ if (m_stat == 0)
1174
+ {
1175
+ if (m_impl->filterPtr)
1176
+ {
1177
+ m_impl->filterPtr->setPosTypeNext(false);
1178
+ getRecords(TD_POS_PREV_MULTI);
1179
+ }
1146
1180
  }
1147
1181
  }
1148
1182
  }
1149
1183
 
1150
1184
  void table::findNext(bool notIncCurrent)
1151
1185
  {
1152
-
1153
- if (m_impl->filterPtr)
1186
+ if (m_keynum >= 0)
1154
1187
  {
1155
- short op = m_impl->filterPtr->isSeeksMode() ? TD_KEY_SEEK_MULTI
1156
- : TD_KEY_NEXT_MULTI;
1157
- doFind(op, notIncCurrent);
1188
+ if (m_impl->filterPtr)
1189
+ {
1190
+ short op = m_impl->filterPtr->isSeeksMode() ? TD_KEY_SEEK_MULTI
1191
+ : TD_KEY_NEXT_MULTI;
1192
+ doFind(op, notIncCurrent);
1193
+ }
1194
+ else if (notIncCurrent == true)
1195
+ seekNext();
1196
+ }else
1197
+ {
1198
+ if (m_impl->filterPtr)
1199
+ doFind(TD_POS_NEXT_MULTI, notIncCurrent);
1200
+ else if (notIncCurrent == true)
1201
+ stepNext();
1158
1202
  }
1159
- else if (notIncCurrent == true)
1160
- seekNext();
1161
1203
  }
1162
1204
 
1163
1205
  void table::findPrev(bool notIncCurrent)
1164
1206
  {
1165
- if (m_impl->filterPtr)
1166
- doFind(TD_KEY_PREV_MULTI, notIncCurrent);
1167
- else if (notIncCurrent == true)
1168
- seekPrev();
1207
+ if (m_keynum >= 0)
1208
+ {
1209
+ if (m_impl->filterPtr)
1210
+ doFind(TD_KEY_PREV_MULTI, notIncCurrent);
1211
+ else if (notIncCurrent == true)
1212
+ seekPrev();
1213
+ }else
1214
+ {
1215
+ if (m_impl->filterPtr)
1216
+ doFind(TD_POS_PREV_MULTI, notIncCurrent);
1217
+ else if (notIncCurrent == true)
1218
+ stepPrev();
1219
+ }
1169
1220
  }
1170
1221
 
1171
1222
  void table::setPrepare(const pq_handle stmt)
@@ -1269,14 +1269,23 @@ typedef transaction<dbmanager_ptr> dbmTransaction;
1269
1269
  template <class DB> class snapshot
1270
1270
  {
1271
1271
  DB m_db;
1272
+ bool m_started;
1272
1273
 
1273
1274
  public:
1274
1275
  snapshot(DB db, short bias = CONSISTENT_READ, binlogPos* bpos=NULL) : m_db(db)
1275
1276
  {
1276
1277
  m_db->beginSnapshot(bias, bpos);
1278
+ m_started = true;
1277
1279
  }
1278
1280
 
1279
- ~snapshot() { m_db->endSnapshot(); }
1281
+ void end()
1282
+ {
1283
+ if (m_started)
1284
+ m_db->endSnapshot();
1285
+ m_started = false;
1286
+ }
1287
+
1288
+ ~snapshot() { end(); }
1280
1289
  };
1281
1290
 
1282
1291
  /** snapshot for database */