MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ScanFunctions.hpp
1 /*
2  Copyright (C) 2003-2006, 2008 MySQL AB
3  All rights reserved. Use is subject to license terms.
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; version 2 of the License.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 
19 #include <NDBT.hpp>
20 #include <NDBT_Test.hpp>
21 
22 
23 
24 struct Attrib {
25  int numAttribs;
26  int attribs[1024];
27 };
28 class AttribList {
29 public:
30  AttribList(){};
31  ~AttribList(){
32  for(size_t i = 0; i < attriblist.size(); i++){
33  delete attriblist[i];
34  }
35  };
36  void buildAttribList(const NdbDictionary::Table* pTab);
37  Vector<Attrib*> attriblist;
38 };
39 
40 
41 // Functions that help out in testing that we may call
42 // scan functions in wrong order etc
43 // and receive a proper errormessage
45 public:
46  ScanFunctions(const NdbDictionary::Table& _tab) : tab(_tab){
47  }
48  enum ActionType {
49  CloseWithoutStop,
50  NextScanWhenNoMore,
51  ExecuteScanWithOutOpenScan,
52  OnlyOneScanPerTrans,
53  OnlyOneOpBeforeOpenScan,
54  OnlyOpenScanOnce,
55  OnlyOneOpInScanTrans,
56  CheckInactivityTimeOut,
57  CheckInactivityBeforeClose ,
58  NoCloseTransaction,
59  EqualAfterOpenScan
60  };
61 
62 
63  int scanReadFunctions(Ndb* pNdb,
64  int records,
65  int parallelism,
66  ActionType action,
67  bool exclusive);
68 private:
69  const NdbDictionary::Table& tab;
70 };
71 
72 
73 inline
74 int
75 ScanFunctions::scanReadFunctions(Ndb* pNdb,
76  int records,
77  int parallelism,
78  ActionType action,
79  bool exclusive){
80  int retryAttempt = 0;
81  const int retryMax = 100;
82  int sleepTime = 10;
83  int check;
84  NdbConnection *pTrans = 0;
85  NdbScanOperation *pOp = 0;
86 
87  while (true){
88  if (retryAttempt >= retryMax){
89  g_err << "ERROR: has retried this operation " << retryAttempt
90  << " times, failing!" << endl;
91  return NDBT_FAILED;
92  }
93 
94  pTrans = pNdb->startTransaction();
95  if (pTrans == NULL) {
96  const NdbError err = pNdb->getNdbError();
97  if (err.status == NdbError::TemporaryError){
98  ERR(err);
99  NdbSleep_MilliSleep(50);
100  retryAttempt++;
101  continue;
102  }
103  ERR(err);
104  return NDBT_FAILED;
105  }
106 
107  // Execute the scan without defining a scan operation
108  pOp = pTrans->getNdbScanOperation(tab.getName());
109  if (pOp == NULL) {
110  ERR(pTrans->getNdbError());
111  pNdb->closeTransaction(pTrans);
112  return NDBT_FAILED;
113  }
114 
115  if( pOp->readTuples(exclusive ?
118  ERR(pTrans->getNdbError());
119  pNdb->closeTransaction(pTrans);
120  return NDBT_FAILED;
121  }
122 
123 
124  if (action == OnlyOpenScanOnce){
125  // Call openScan one more time when it's already defined
126  if( pOp->readTuples(NdbScanOperation::LM_Read) ) {
127  ERR(pTrans->getNdbError());
128  pNdb->closeTransaction(pTrans);
129  return NDBT_FAILED;
130  }
131  }
132 
133  if (action==EqualAfterOpenScan){
134  check = pOp->equal(tab.getColumn(0)->getName(), 10);
135  if( check == -1 ) {
136  ERR(pTrans->getNdbError());
137  pNdb->closeTransaction(pTrans);
138  return NDBT_FAILED;
139  }
140  }
141 
142  for(int a = 0; a<tab.getNoOfColumns(); a++){
143  if(pOp->getValue(tab.getColumn(a)->getName()) == NULL) {
144  ERR(pTrans->getNdbError());
145  pNdb->closeTransaction(pTrans);
146  return NDBT_FAILED;
147  }
148  }
149 
150  check = pTrans->execute(NoCommit);
151  if( check == -1 ) {
152  ERR(pTrans->getNdbError());
153  pNdb->closeTransaction(pTrans);
154  return NDBT_FAILED;
155  }
156 
157  int abortCount = records / 10;
158  bool abortTrans = (action==CloseWithoutStop);
159  int eof;
160  int rows = 0;
161  eof = pOp->nextResult();
162 
163  while(eof == 0){
164  rows++;
165 
166  if (abortCount == rows && abortTrans == true){
167  g_info << "Scan is aborted after "<<abortCount<<" rows" << endl;
168 
169  if (action != CloseWithoutStop){
170  // Test that we can closeTrans without stopScan
171  pOp->close();
172  if( check == -1 ) {
173  ERR(pTrans->getNdbError());
174  pNdb->closeTransaction(pTrans);
175  return NDBT_FAILED;
176  }
177  }
178 
179 
180  pNdb->closeTransaction(pTrans);
181  return NDBT_OK;
182  }
183 
184  if(action == CheckInactivityTimeOut){
185  if ((rows % (records / 10)) == 0){
186  // Sleep for a long time before calling nextScanResult
187  if (sleepTime > 1)
188  sleepTime--;
189  g_info << "Sleeping "<<sleepTime<<" secs " << endl;
190  NdbSleep_SecSleep(sleepTime);
191  }
192  }
193 
194  eof = pOp->nextResult();
195  }
196  if (eof == -1) {
197  const NdbError err = pTrans->getNdbError();
198 
199  if (err.status == NdbError::TemporaryError){
200  ERR(err);
201 
202  // Be cruel, call nextScanResult after error
203  for(int i=0; i<10; i++){
204  eof = pOp->nextResult();
205  if(eof == 0){
206  g_err << "nextScanResult returned eof = " << eof << endl
207  << " That is an error when there are no more records" << endl;
208  return NDBT_FAILED;
209  }
210  }
211  // Be cruel end
212 
213  pNdb->closeTransaction(pTrans);
214  NdbSleep_MilliSleep(50);
215  retryAttempt++;
216  g_info << "Starting over" << endl;
217 
218  // If test is CheckInactivityTimeOut
219  // error 296 is expected
220  if ((action == CheckInactivityTimeOut) &&
221  (err.code == 296))
222  return NDBT_OK;
223 
224  continue;
225  }
226  ERR(err);
227  pNdb->closeTransaction(pTrans);
228  return NDBT_FAILED;
229  }
230 
231  if (action == NextScanWhenNoMore){
232  g_info << "Calling nextScanresult when there are no more records" << endl;
233  for(int i=0; i<10; i++){
234  eof = pOp->nextResult();
235  if(eof == 0){
236  g_err << "nextScanResult returned eof = " << eof << endl
237  << " That is an error when there are no more records" << endl;
238  return NDBT_FAILED;
239  }
240  }
241 
242  }
243  if(action == CheckInactivityBeforeClose){
244  // Sleep for a long time before calling close
245  g_info << "NdbSleep_SecSleep(5) before close transaction" << endl;
246  NdbSleep_SecSleep(5);
247  }
248  if(action == NoCloseTransaction)
249  g_info << "Forgetting to close transaction" << endl;
250  else
251  pNdb->closeTransaction(pTrans);
252 
253  g_info << rows << " rows have been read" << endl;
254  if (records != 0 && rows != records){
255  g_err << "Check expected number of records failed" << endl
256  << " expected=" << records <<", " << endl
257  << " read=" << rows << endl;
258  return NDBT_FAILED;
259  }
260 
261  return NDBT_OK;
262  }
263  return NDBT_FAILED;
264 
265 
266 }
267 
268 void AttribList::buildAttribList(const NdbDictionary::Table* pTab){
269  attriblist.clear();
270 
271  Attrib* attr;
272  // Build attrib definitions that describes which attributes to read
273  // Try to build strange combinations, not just "all" or all PK's
274 
275  // Scan without reading any attributes
276  attr = new Attrib;
277  attr->numAttribs = 0;
278  attriblist.push_back(attr);
279  int i;
280  for(i = 1; i < pTab->getNoOfColumns(); i++){
281  attr = new Attrib;
282  attr->numAttribs = i;
283  for(int a = 0; a<i; a++)
284  attr->attribs[a] = a;
285  attriblist.push_back(attr);
286  }
287  for(i = pTab->getNoOfColumns()-1; i > 0; i--){
288  attr = new Attrib;
289  attr->numAttribs = i;
290  for(int a = 0; a<i; a++)
291  attr->attribs[a] = a;
292  attriblist.push_back(attr);
293  }
294  for(i = pTab->getNoOfColumns(); i > 0; i--){
295  attr = new Attrib;
296  attr->numAttribs = pTab->getNoOfColumns() - i;
297  for(int a = 0; a<pTab->getNoOfColumns() - i; a++)
298  attr->attribs[a] = pTab->getNoOfColumns()-a-1;
299  attriblist.push_back(attr);
300  }
301  for(i = 1; i < pTab->getNoOfColumns(); i++){
302  attr = new Attrib;
303  attr->numAttribs = pTab->getNoOfColumns() - i;
304  for(int a = 0; a<pTab->getNoOfColumns() - i; a++)
305  attr->attribs[a] = pTab->getNoOfColumns()-a-1;
306  attriblist.push_back(attr);
307  }
308  for(i = 1; i < pTab->getNoOfColumns(); i++){
309  attr = new Attrib;
310  attr->numAttribs = 2;
311  for(int a = 0; a<2; a++){
312  attr->attribs[a] = i%pTab->getNoOfColumns();
313  }
314  attriblist.push_back(attr);
315  }
316 
317  // Last
318  attr = new Attrib;
319  attr->numAttribs = 1;
320  attr->attribs[0] = pTab->getNoOfColumns()-1;
321  attriblist.push_back(attr);
322 
323  // Last and first
324  attr = new Attrib;
325  attr->numAttribs = 2;
326  attr->attribs[0] = pTab->getNoOfColumns()-1;
327  attr->attribs[1] = 0;
328  attriblist.push_back(attr);
329 
330  // First and last
331  attr = new Attrib;
332  attr->numAttribs = 2;
333  attr->attribs[0] = 0;
334  attr->attribs[1] = pTab->getNoOfColumns()-1;
335  attriblist.push_back(attr);
336 
337 #if 1
338  for(size_t j = 0; j < attriblist.size(); j++){
339 
340  g_info << attriblist[j]->numAttribs << ": " ;
341  for(int a = 0; a < attriblist[j]->numAttribs; a++)
342  g_info << attriblist[j]->attribs[a] << ", ";
343  g_info << endl;
344  }
345 #endif
346 
347 }