1 /*
2    Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #include <ndb_global.h>
26 #include <AttributeHeader.hpp>
27 #include <NdbSqlUtil.hpp>
28 #include <NdbIndexStat.hpp>
29 #include <NdbTransaction.hpp>
30 #include "NdbDictionaryImpl.hpp"
31 #include <NdbInterpretedCode.hpp>
32 #include <NdbRecord.hpp>
33 #include "NdbIndexStatImpl.hpp"
34 
NdbIndexStat()35 NdbIndexStat::NdbIndexStat() :
36   m_impl(*new NdbIndexStatImpl(*this))
37 {
38 }
39 
NdbIndexStat(NdbIndexStatImpl & impl)40 NdbIndexStat::NdbIndexStat(NdbIndexStatImpl& impl) :
41   m_impl(impl)
42 {
43 }
44 
~NdbIndexStat()45 NdbIndexStat::~NdbIndexStat()
46 {
47   NdbIndexStatImpl* impl = &m_impl;
48   if (this != impl)
49     delete impl;
50 }
51 
52 /**
53  * addKeyPartInfo
54  * This method is used to build a standard representation of a
55  * lower or upper index bound in a buffer, which can then
56  * be used to identify a range.
57  * The buffer format is :
58  *   1 word of NdbIndexScanOperation::BoundType
59  *   1 word of ATTRINFO header containing the index attrid
60  *     and the size in words of the data.
61  *   0..N words of data.
62  * The data itself is formatted as usual (e.g. 1/2 length
63  * bytes for VAR* types)
64  * For NULLs, length==0
65  */
66 
67 int
addKeyPartInfo(const NdbRecord * record,const char * keyRecordData,Uint32 keyPartNum,const NdbIndexScanOperation::BoundType boundType,Uint32 * keyStatData,Uint32 & keyLength)68 NdbIndexStat::addKeyPartInfo(const NdbRecord* record,
69                              const char* keyRecordData,
70                              Uint32 keyPartNum,
71                              const NdbIndexScanOperation::BoundType boundType,
72                              Uint32* keyStatData,
73                              Uint32& keyLength)
74 {
75   char buf[NdbRecord::Attr::SHRINK_VARCHAR_BUFFSIZE];
76 
77   Uint32 key_index= record->key_indexes[ keyPartNum ];
78   const NdbRecord::Attr *column= &record->columns[ key_index ];
79 
80   bool is_null= column->is_null(keyRecordData);
81   Uint32 len= 0;
82   const void *aValue= keyRecordData + column->offset;
83 
84   if (!is_null)
85   {
86     bool len_ok;
87     /* Support for special mysqld varchar format in keys. */
88     if (column->flags & NdbRecord::IsMysqldShrinkVarchar)
89     {
90       len_ok= column->shrink_varchar(keyRecordData,
91                                      len,
92                                      buf);
93       aValue= buf;
94     }
95     else
96     {
97       len_ok= column->get_var_length(keyRecordData, len);
98     }
99     if (!len_ok) {
100       m_impl.setError(4209, __LINE__);
101       return -1;
102     }
103   }
104 
105   /* Insert attribute header. */
106   Uint32 tIndexAttrId= column->index_attrId;
107   Uint32 sizeInWords= (len + 3) / 4;
108   AttributeHeader ah(tIndexAttrId, sizeInWords << 2);
109   const Uint32 ahValue= ah.m_value;
110 
111   if (keyLength + (2 + len) > NdbIndexStatImpl::BoundBufWords )
112   {
113     /* Something wrong, key data would be too big */
114     /* Key size is limited to 4092 bytes */
115     m_impl.setError(4207, __LINE__);
116     return -1;
117   }
118 
119   /* Fill in key data */
120   keyStatData[ keyLength++ ]= boundType;
121   keyStatData[ keyLength++ ]= ahValue;
122   /* Zero last word prior to byte copy, in case we're not aligned */
123   keyStatData[ keyLength + sizeInWords - 1] = 0;
124   memcpy(&keyStatData[ keyLength ], aValue, len);
125 
126   keyLength+= sizeInWords;
127 
128   return 0;
129 }
130 
131 int
records_in_range(const NdbDictionary::Index * index,NdbTransaction * trans,const NdbRecord * key_record,const NdbRecord * result_record,const NdbIndexScanOperation::IndexBound * ib,Uint64 table_rows,Uint64 * count,int flags)132 NdbIndexStat::records_in_range(const NdbDictionary::Index* index,
133                                NdbTransaction* trans,
134                                const NdbRecord* key_record,
135                                const NdbRecord* result_record,
136                                const NdbIndexScanOperation::IndexBound* ib,
137                                Uint64 table_rows,
138                                Uint64* count,
139                                int flags)
140 {
141   DBUG_ENTER("NdbIndexStat::records_in_range");
142   Uint64 rows;
143   Uint32 key1[NdbIndexStatImpl::BoundBufWords], keylen1;
144   Uint32 key2[NdbIndexStatImpl::BoundBufWords], keylen2;
145 
146   if (true)
147   {
148     // get start and end key from NdbIndexBound, using NdbRecord to
149     // get values into a standard format.
150     Uint32 maxBoundParts= (ib->low_key_count > ib->high_key_count) ?
151       ib->low_key_count : ib->high_key_count;
152 
153     keylen1= keylen2= 0;
154 
155     /* Fill in keyX buffers */
156     for (Uint32 keyPartNum=0; keyPartNum < maxBoundParts; keyPartNum++)
157     {
158       if (ib->low_key_count > keyPartNum)
159       {
160         /* Set bound to LT only if it's not inclusive
161          * and this is the last key
162          */
163         NdbIndexScanOperation::BoundType boundType=
164           NdbIndexScanOperation::BoundLE;
165         if ((! ib->low_inclusive) &&
166             (keyPartNum == (ib->low_key_count -1 )))
167           boundType= NdbIndexScanOperation::BoundLT;
168 
169         if (addKeyPartInfo(key_record,
170                            ib->low_key,
171                            keyPartNum,
172                            boundType,
173                            key1,
174                            keylen1) != 0)
175           DBUG_RETURN(-1);
176       }
177       if (ib->high_key_count > keyPartNum)
178       {
179         /* Set bound to GT only if it's not inclusive
180          * and this is the last key
181          */
182         NdbIndexScanOperation::BoundType boundType=
183           NdbIndexScanOperation::BoundGE;
184         if ((! ib->high_inclusive) &&
185             (keyPartNum == (ib->high_key_count -1)))
186           boundType= NdbIndexScanOperation::BoundGT;
187 
188         if (addKeyPartInfo(key_record,
189                            ib->high_key,
190                            keyPartNum,
191                            boundType,
192                            key2,
193                            keylen2) != 0)
194           DBUG_RETURN(-1);
195       }
196     }
197   }
198 
199   if (true)
200   {
201     Uint32 out[4] = { 0, 0, 0, 0 };  // rows, in, before, after
202     float tot[4] = { 0, 0, 0, 0 };   // totals of above
203     int cnt, ret;
204     bool forceSend = true;
205     const Uint32 codeWords= 1;
206     Uint32 codeSpace[ codeWords ];
207     NdbInterpretedCode code(NULL, // No table
208                             &codeSpace[0],
209                             codeWords);
210     if ((code.interpret_exit_last_row() != 0) ||
211         (code.finalise() != 0))
212     {
213       m_impl.setError(code.getNdbError().code, __LINE__);
214       DBUG_PRINT("error", ("code: %d", code.getNdbError().code));
215       DBUG_RETURN(-1);
216     }
217 
218     NdbIndexScanOperation* op= NULL;
219     NdbScanOperation::ScanOptions options;
220     NdbOperation::GetValueSpec extraGet;
221 
222     options.optionsPresent=
223       NdbScanOperation::ScanOptions::SO_GETVALUE |
224       NdbScanOperation::ScanOptions::SO_INTERPRETED;
225 
226     /* Read RECORDS_IN_RANGE pseudo column */
227     extraGet.column= NdbDictionary::Column::RECORDS_IN_RANGE;
228     extraGet.appStorage= (void*) out;
229     extraGet.recAttr= NULL;
230 
231     options.extraGetValues= &extraGet;
232     options.numExtraGetValues= 1;
233 
234     /* Add interpreted code to return on 1st row */
235     options.interpretedCode= &code;
236 
237     const Uint32 keyBitmaskWords= (NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY + 31) >> 5;
238     Uint32 emptyMask[keyBitmaskWords];
239     memset(&emptyMask[0], 0, keyBitmaskWords << 2);
240 
241     if (NULL ==
242         (op= trans->scanIndex(key_record,
243                               result_record,
244                               NdbOperation::LM_CommittedRead,
245                               (const unsigned char*) &emptyMask[0],
246                               ib,
247                               &options,
248                               sizeof(NdbScanOperation::ScanOptions))))
249     {
250       m_impl.setError(trans->getNdbError().code, __LINE__);
251       DBUG_PRINT("error", ("scanIndex : %d", trans->getNdbError().code));
252       DBUG_RETURN(-1);
253     }
254 
255     if (trans->execute(NdbTransaction::NoCommit,
256                        NdbOperation::AbortOnError, forceSend) == -1) {
257       m_impl.setError(trans->getNdbError().code, __LINE__);
258       DBUG_PRINT("error", ("trans:%d op:%d", trans->getNdbError().code,
259                            op->getNdbError().code));
260       DBUG_RETURN(-1);
261     }
262     cnt = 0;
263     const char* dummy_out_ptr= NULL;
264     while ((ret = op->nextResult(&dummy_out_ptr,
265                                  true, forceSend)) == 0) {
266       DBUG_PRINT("info", ("frag rows=%u in=%u before=%u after=%u [error=%d]",
267                           out[0], out[1], out[2], out[3],
268                           (int)(out[1] + out[2] + out[3]) - (int)out[0]));
269       unsigned i;
270       for (i = 0; i < 4; i++)
271         tot[i] += (float)out[i];
272       cnt++;
273     }
274     if (ret == -1) {
275       m_impl.setError(op->getNdbError().code, __LINE__);
276       DBUG_PRINT("error nextResult ", ("trans:%d op:%d", trans->getNdbError().code,
277                            op->getNdbError().code));
278       DBUG_RETURN(-1);
279     }
280     op->close(forceSend);
281     rows = (Uint64)tot[1];
282   }
283 
284   *count = rows;
285   DBUG_PRINT("value", ("rows=%u/%u flags=%x",
286                        (unsigned)(rows>>32), (unsigned)(rows), flags));
287   DBUG_RETURN(0);
288 }
289 
290 // stored stats
291 
292 int
create_systables(Ndb * ndb)293 NdbIndexStat::create_systables(Ndb* ndb)
294 {
295   DBUG_ENTER("NdbIndexStat::create_systables");
296   if (m_impl.create_systables(ndb) == -1)
297     DBUG_RETURN(-1);
298   DBUG_RETURN(0);
299 }
300 
301 int
drop_systables(Ndb * ndb)302 NdbIndexStat::drop_systables(Ndb* ndb)
303 {
304   DBUG_ENTER("NdbIndexStat::drop_systables");
305   if (m_impl.drop_systables(ndb) == -1)
306     DBUG_RETURN(-1);
307   DBUG_RETURN(0);
308 }
309 
310 int
check_systables(Ndb * ndb)311 NdbIndexStat::check_systables(Ndb* ndb)
312 {
313   DBUG_ENTER("NdbIndexStat::check_systables");
314   if (m_impl.check_systables(ndb) == -1)
315     DBUG_RETURN(-1);
316   DBUG_RETURN(0);
317 }
318 
319 int
set_index(const NdbDictionary::Index & index,const NdbDictionary::Table & table)320 NdbIndexStat::set_index(const NdbDictionary::Index& index,
321                         const NdbDictionary::Table& table)
322 {
323   DBUG_ENTER("NdbIndexStat::set_index");
324   if (m_impl.set_index(index, table) == -1)
325     DBUG_RETURN(-1);
326   m_impl.m_facadeHead.m_indexId = index.getObjectId();
327   m_impl.m_facadeHead.m_indexVersion = index.getObjectVersion();
328   m_impl.m_facadeHead.m_tableId = table.getObjectId();
329   DBUG_RETURN(0);
330 }
331 
332 void
reset_index()333 NdbIndexStat::reset_index()
334 {
335   DBUG_ENTER("NdbIndexStat::reset_index");
336   m_impl.reset_index();
337   DBUG_VOID_RETURN;
338 }
339 
340 int
update_stat(Ndb * ndb)341 NdbIndexStat::update_stat(Ndb* ndb)
342 {
343   DBUG_ENTER("NdbIndexStat::update_stat");
344   if (m_impl.update_stat(ndb, m_impl.m_facadeHead) == -1)
345     DBUG_RETURN(-1);
346   DBUG_RETURN(0);
347 }
348 
349 int
delete_stat(Ndb * ndb)350 NdbIndexStat::delete_stat(Ndb* ndb)
351 {
352   DBUG_ENTER("NdbIndexStat::delete_stat");
353   if (m_impl.delete_stat(ndb, m_impl.m_facadeHead) == -1)
354     DBUG_RETURN(-1);
355   DBUG_RETURN(0);
356 }
357 
358 // cache
359 
360 void
move_cache()361 NdbIndexStat::move_cache()
362 {
363   DBUG_ENTER("NdbIndexStat::move_cache");
364   m_impl.move_cache();
365   DBUG_VOID_RETURN;
366 }
367 
368 void
clean_cache()369 NdbIndexStat::clean_cache()
370 {
371   DBUG_ENTER("NdbIndexStat::clean_cache");
372   m_impl.clean_cache();
373   DBUG_VOID_RETURN;
374 }
375 
376 void
get_cache_info(CacheInfo & info,CacheType type) const377 NdbIndexStat::get_cache_info(CacheInfo& info, CacheType type) const
378 {
379   const NdbIndexStatImpl::Cache* c = 0;
380   switch (type) {
381   case CacheBuild:
382     c = m_impl.m_cacheBuild;
383     break;
384   case CacheQuery:
385     c = m_impl.m_cacheQuery;
386     break;
387   case CacheClean:
388     c = m_impl.m_cacheClean;
389     break;
390   }
391   info.m_count = 0;
392   info.m_valid = 0;
393   info.m_sampleCount = 0;
394   info.m_totalBytes = 0;
395   info.m_save_time = 0;
396   info.m_sort_time = 0;
397   while (c != 0)
398   {
399     info.m_count += 1;
400     info.m_valid += c->m_valid;
401     info.m_sampleCount += c->m_sampleCount;
402     info.m_totalBytes += c->m_keyBytes + c->m_valueBytes + c->m_addrBytes;
403     info.m_save_time += c->m_save_time;
404     info.m_sort_time += c->m_sort_time;
405     c = c->m_nextClean;
406   }
407   // build and query cache have at most one instance
408   require(type == CacheClean || info.m_count <= 1);
409 }
410 
411 // read
412 
413 void
get_head(Head & head) const414 NdbIndexStat::get_head(Head& head) const
415 {
416   head = m_impl.m_facadeHead;
417 }
418 
419 int
read_head(Ndb * ndb)420 NdbIndexStat::read_head(Ndb* ndb)
421 {
422   DBUG_ENTER("NdbIndexStat::read_head");
423   if (m_impl.read_head(ndb, m_impl.m_facadeHead) == -1)
424     DBUG_RETURN(-1);
425   DBUG_RETURN(0);
426 }
427 
428 int
read_stat(Ndb * ndb)429 NdbIndexStat::read_stat(Ndb* ndb)
430 {
431   DBUG_ENTER("NdbIndexStat::read_stat");
432   if (m_impl.read_stat(ndb, m_impl.m_facadeHead) == -1)
433     DBUG_RETURN(-1);
434   DBUG_RETURN(0);
435 }
436 
437 // bound
438 
Bound(const NdbIndexStat * is,void * buffer)439 NdbIndexStat::Bound::Bound(const NdbIndexStat* is, void* buffer)
440 {
441   DBUG_ENTER("NdbIndexStat::Bound::Bound");
442   require(is != 0 && is->m_impl.m_indexSet);
443   require(buffer != 0);
444   Uint8* buf = (Uint8*)buffer;
445   // bound impl
446   Uint8* buf1 = buf;
447   UintPtr ubuf1 = (UintPtr)buf1;
448   if (ubuf1 % 8 != 0)
449     buf1 += (8 - ubuf1 % 8);
450   new (buf1) NdbIndexStatImpl::Bound(is->m_impl.m_keySpec);
451   m_impl = (void*)buf1;
452   NdbIndexStatImpl::Bound& bound = *(NdbIndexStatImpl::Bound*)m_impl;
453   // bound data
454   Uint8* buf2 = buf1 + sizeof(NdbIndexStatImpl::Bound);
455   uint used = (uint)(buf2 - buf);
456   uint bytes = BoundBufferBytes - used;
457   bound.m_data.set_buf(buf2, bytes);
458   DBUG_VOID_RETURN;
459 }
460 
461 int
add_bound(Bound & bound_f,const void * value)462 NdbIndexStat::add_bound(Bound& bound_f, const void* value)
463 {
464   DBUG_ENTER("NdbIndexStat::add_bound");
465   NdbIndexStatImpl::Bound& bound =
466     *(NdbIndexStatImpl::Bound*)bound_f.m_impl;
467   Uint32 len_out;
468   if (value == 0)
469   {
470     m_impl.setError(UsageError, __LINE__);
471     DBUG_RETURN(-1);
472   }
473   if (bound.m_data.add(value, &len_out) == -1)
474   {
475     m_impl.setError(UsageError, __LINE__);
476     DBUG_RETURN(-1);
477   }
478   DBUG_RETURN(0);
479 }
480 
481 int
add_bound_null(Bound & bound_f)482 NdbIndexStat::add_bound_null(Bound& bound_f)
483 {
484   DBUG_ENTER("NdbIndexStat::add_bound_null");
485   NdbIndexStatImpl::Bound& bound =
486     *(NdbIndexStatImpl::Bound*)bound_f.m_impl;
487   Uint32 len_out;
488   if (bound.m_data.add_null(&len_out) == -1)
489   {
490     m_impl.setError(UsageError, __LINE__);
491     DBUG_RETURN(-1);
492   }
493   DBUG_RETURN(0);
494 }
495 
496 void
set_bound_strict(Bound & bound_f,int strict)497 NdbIndexStat::set_bound_strict(Bound& bound_f, int strict)
498 {
499   DBUG_ENTER("NdbIndexStat::set_bound_strict");
500   NdbIndexStatImpl::Bound& bound =
501     *(NdbIndexStatImpl::Bound*)bound_f.m_impl;
502   bound.m_strict = strict;
503   DBUG_VOID_RETURN;
504 }
505 
506 void
reset_bound(Bound & bound_f)507 NdbIndexStat::reset_bound(Bound& bound_f)
508 {
509   DBUG_ENTER("NdbIndexStat::reset_bound");
510   NdbIndexStatImpl::Bound& bound =
511     *(NdbIndexStatImpl::Bound*)bound_f.m_impl;
512   bound.m_bound.reset();
513   bound.m_type = -1;
514   bound.m_strict = -1;
515   DBUG_VOID_RETURN;
516 }
517 
518 // range
519 
Range(Bound & bound1,Bound & bound2)520 NdbIndexStat::Range::Range(Bound& bound1, Bound& bound2) :
521   m_bound1(bound1),
522   m_bound2(bound2)
523 {
524   DBUG_ENTER("NdbIndexStat::Range::Range");
525   DBUG_VOID_RETURN;
526 }
527 
528 int
finalize_range(Range & range_f)529 NdbIndexStat::finalize_range(Range& range_f)
530 {
531   DBUG_ENTER("NdbIndexStat::finalize_range");
532   Bound& bound1_f = range_f.m_bound1;
533   Bound& bound2_f = range_f.m_bound2;
534   NdbIndexStatImpl::Bound& bound1 =
535     *(NdbIndexStatImpl::Bound*)bound1_f.m_impl;
536   NdbIndexStatImpl::Bound& bound2 =
537     *(NdbIndexStatImpl::Bound*)bound2_f.m_impl;
538   NdbIndexStatImpl::Range range(bound1, bound2);
539   if (m_impl.finalize_range(range) == -1)
540     DBUG_RETURN(-1);
541   DBUG_RETURN(0);
542 }
543 
544 void
reset_range(Range & range)545 NdbIndexStat::reset_range(Range& range)
546 {
547   DBUG_ENTER("NdbIndexStat::reset_range");
548   reset_bound(range.m_bound1);
549   reset_bound(range.m_bound2);
550   DBUG_VOID_RETURN;
551 }
552 
553 int
convert_range(Range & range_f,const NdbRecord * key_record,const NdbIndexScanOperation::IndexBound * ib)554 NdbIndexStat::convert_range(Range& range_f,
555                             const NdbRecord* key_record,
556                             const NdbIndexScanOperation::IndexBound* ib)
557 {
558   DBUG_ENTER("NdbIndexStat::convert_range");
559   Bound& bound1_f = range_f.m_bound1;
560   Bound& bound2_f = range_f.m_bound2;
561   NdbIndexStatImpl::Bound& bound1 =
562     *(NdbIndexStatImpl::Bound*)bound1_f.m_impl;
563   NdbIndexStatImpl::Bound& bound2 =
564     *(NdbIndexStatImpl::Bound*)bound2_f.m_impl;
565   NdbIndexStatImpl::Range range(bound1, bound2);
566   if (m_impl.convert_range(range, key_record, ib) == -1)
567     DBUG_RETURN(-1);
568   DBUG_RETURN(0);
569 }
570 
571 // stat
572 
Stat(void * buffer)573 NdbIndexStat::Stat::Stat(void* buffer)
574 {
575   DBUG_ENTER("NdbIndexStat::Stat::Stat");
576   require(buffer != 0);
577   Uint8* buf = (Uint8*)buffer;
578   // stat impl
579   Uint8* buf1 = buf;
580   UintPtr ubuf1 = (UintPtr)buf1;
581   if (ubuf1 % 8 != 0)
582     buf1 += (8 - ubuf1 % 8);
583   new (buf1) NdbIndexStatImpl::Stat;
584   m_impl = (void*)buf1;
585   DBUG_VOID_RETURN;
586 }
587 
588 int
query_stat(const Range & range_f,Stat & stat_f)589 NdbIndexStat::query_stat(const Range& range_f, Stat& stat_f)
590 {
591   DBUG_ENTER("NdbIndexStat::query_stat");
592   Bound& bound1_f = range_f.m_bound1;
593   Bound& bound2_f = range_f.m_bound2;
594   NdbIndexStatImpl::Bound& bound1 =
595     *(NdbIndexStatImpl::Bound*)bound1_f.m_impl;
596   NdbIndexStatImpl::Bound& bound2 =
597     *(NdbIndexStatImpl::Bound*)bound2_f.m_impl;
598   NdbIndexStatImpl::Range range(bound1, bound2);
599 #ifndef DBUG_OFF
600   const uint sz = 8000;
601   char buf[sz];
602   DBUG_PRINT("index_stat", ("lo: %s", bound1.m_bound.print(buf, sz)));
603   DBUG_PRINT("index_stat", ("hi: %s", bound2.m_bound.print(buf, sz)));
604 #endif
605   NdbIndexStatImpl::Stat& stat =
606     *(NdbIndexStatImpl::Stat*)stat_f.m_impl;
607   if (m_impl.query_stat(range, stat) == -1)
608     DBUG_RETURN(-1);
609   DBUG_RETURN(0);
610 }
611 
612 void
get_empty(const Stat & stat_f,bool * empty)613 NdbIndexStat::get_empty(const Stat& stat_f, bool* empty)
614 {
615   DBUG_ENTER("NdbIndexStat::get_empty");
616   const NdbIndexStatImpl::Stat& stat =
617     *(const NdbIndexStatImpl::Stat*)stat_f.m_impl;
618   require(empty != 0);
619   *empty = stat.m_value.m_empty;
620   DBUG_PRINT("index_stat", ("empty:%d", *empty));
621   DBUG_VOID_RETURN;
622 }
623 
624 void
get_rir(const Stat & stat_f,double * rir)625 NdbIndexStat::get_rir(const Stat& stat_f, double* rir)
626 {
627   DBUG_ENTER("NdbIndexStat::get_rir");
628   const NdbIndexStatImpl::Stat& stat =
629     *(const NdbIndexStatImpl::Stat*)stat_f.m_impl;
630   double x = stat.m_value.m_rir;
631   if (x < 1.0)
632     x = 1.0;
633   require(rir != 0);
634   *rir = x;
635 #ifndef DBUG_OFF
636   char buf[100];
637   sprintf(buf, "%.2f", *rir);
638 #endif
639   DBUG_PRINT("index_stat", ("rir:%s", buf));
640   DBUG_VOID_RETURN;
641 }
642 
643 void
get_rpk(const Stat & stat_f,Uint32 k,double * rpk)644 NdbIndexStat::get_rpk(const Stat& stat_f, Uint32 k, double* rpk)
645 {
646   DBUG_ENTER("NdbIndexStat::get_rpk");
647   const NdbIndexStatImpl::Stat& stat =
648     *(const NdbIndexStatImpl::Stat*)stat_f.m_impl;
649   double x = stat.m_value.m_rir / stat.m_value.m_unq[k];
650   if (x < 1.0)
651     x = 1.0;
652   require(rpk != 0);
653   *rpk = x;
654 #ifndef DBUG_OFF
655   char buf[100];
656   sprintf(buf, "%.2f", *rpk);
657 #endif
658   DBUG_PRINT("index_stat", ("rpk[%u]:%s", k, buf));
659   DBUG_VOID_RETURN;
660 }
661 
662 void
get_rule(const Stat & stat_f,char * buffer)663 NdbIndexStat::get_rule(const Stat& stat_f, char* buffer)
664 {
665   DBUG_ENTER("NdbIndexStat::get_rule");
666   const NdbIndexStatImpl::Stat& stat =
667     *(const NdbIndexStatImpl::Stat*)stat_f.m_impl;
668   require(buffer != 0);
669   BaseString::snprintf(buffer, RuleBufferBytes, "%s/%s/%s",
670                        stat.m_rule[0], stat.m_rule[1], stat.m_rule[2]);
671   DBUG_VOID_RETURN;
672 }
673 
674 // events and polling
675 
676 int
create_sysevents(Ndb * ndb)677 NdbIndexStat::create_sysevents(Ndb* ndb)
678 {
679   DBUG_ENTER("NdbIndexStat::create_sysevents");
680   if (m_impl.create_sysevents(ndb) == -1)
681     DBUG_RETURN(-1);
682   DBUG_RETURN(0);
683 }
684 
685 int
drop_sysevents(Ndb * ndb)686 NdbIndexStat::drop_sysevents(Ndb* ndb)
687 {
688   DBUG_ENTER("NdbIndexStat::drop_sysevents");
689   if (m_impl.drop_sysevents(ndb) == -1)
690     DBUG_RETURN(-1);
691   DBUG_RETURN(0);
692 }
693 
694 int
check_sysevents(Ndb * ndb)695 NdbIndexStat::check_sysevents(Ndb* ndb)
696 {
697   DBUG_ENTER("NdbIndexStat::check_sysevents");
698   if (m_impl.check_sysevents(ndb) == -1)
699     DBUG_RETURN(-1);
700   DBUG_RETURN(0);
701 }
702 
703 int
create_listener(Ndb * ndb)704 NdbIndexStat::create_listener(Ndb* ndb)
705 {
706   DBUG_ENTER("NdbIndexStat::create_listener");
707   if (m_impl.create_listener(ndb) == -1)
708     DBUG_RETURN(-1);
709   DBUG_RETURN(0);
710 }
711 
712 int
execute_listener(Ndb * ndb)713 NdbIndexStat::execute_listener(Ndb* ndb)
714 {
715   DBUG_ENTER("NdbIndexStat::execute_listener");
716   if (m_impl.execute_listener(ndb) == -1)
717     DBUG_RETURN(-1);
718   DBUG_RETURN(0);
719 }
720 
721 int
poll_listener(Ndb * ndb,int max_wait_ms)722 NdbIndexStat::poll_listener(Ndb* ndb, int max_wait_ms)
723 {
724   DBUG_ENTER("NdbIndexStat::poll_listener");
725   int ret = m_impl.poll_listener(ndb, max_wait_ms);
726   if (ret == -1)
727     DBUG_RETURN(-1);
728   DBUG_RETURN(ret);
729 }
730 
731 int
next_listener(Ndb * ndb)732 NdbIndexStat::next_listener(Ndb* ndb)
733 {
734   DBUG_ENTER("NdbIndexStat::next_listener");
735   int ret = m_impl.next_listener(ndb);
736   if (ret == -1)
737     DBUG_RETURN(-1);
738   DBUG_RETURN(ret);
739 }
740 
741 int
drop_listener(Ndb * ndb)742 NdbIndexStat::drop_listener(Ndb* ndb)
743 {
744   DBUG_ENTER("NdbIndexStat::drop_listener");
745   if (m_impl.drop_listener(ndb) == -1)
746     DBUG_RETURN(-1);
747   DBUG_RETURN(0);
748 }
749 
750 // mem
751 
Mem()752 NdbIndexStat::Mem::Mem()
753 {
754 }
755 
~Mem()756 NdbIndexStat::Mem::~Mem()
757 {
758 }
759 
760 void
set_mem_handler(Mem * mem)761 NdbIndexStat::set_mem_handler(Mem* mem)
762 {
763   m_impl.m_mem_handler = mem;
764 }
765 
766 // get impl
767 
768 NdbIndexStatImpl&
getImpl()769 NdbIndexStat::getImpl()
770 {
771   return m_impl;
772 }
773 
774 // error
775 
Error()776 NdbIndexStat::Error::Error()
777 {
778   line = 0;
779   extra = 0;
780 }
781 
782 const NdbIndexStat::Error&
getNdbError() const783 NdbIndexStat::getNdbError() const
784 {
785   return m_impl.getNdbError();
786 }
787 
788 class NdbOut&
operator <<(class NdbOut & out,const NdbIndexStat::Error & error)789 operator<<(class NdbOut& out, const NdbIndexStat::Error& error)
790 {
791   out << static_cast<const NdbError&>(error);
792   out << " (line " << error.line << ", extra " << error.extra << ")";
793   return out;
794 }
795