1 /* Copyright (c) 2010, 2021, Oracle and/or its affiliates.
2 
3   This program is free software; you can redistribute it and/or modify
4   it under the terms of the GNU General Public License, version 2.0,
5   as published by the Free Software Foundation.
6 
7   This program is also distributed with certain software (including
8   but not limited to OpenSSL) that is licensed under separate terms,
9   as designated in a particular file or component or in included license
10   documentation.  The authors of MySQL hereby grant you an additional
11   permission to link the program and your derivative works with the
12   separately licensed software that they have included with MySQL.
13 
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License, version 2.0, for more details.
18 
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software Foundation,
21   51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
22 
23 /**
24   @file storage/perfschema/table_events_transactions.cc
25   Table EVENTS_TRANSACTIONS_xxx (implementation).
26 */
27 
28 #include "my_global.h"
29 #include "my_thread.h"
30 #include "table_events_transactions.h"
31 #include "pfs_instr_class.h"
32 #include "pfs_instr.h"
33 #include "pfs_events_transactions.h"
34 #include "pfs_timer.h"
35 #include "table_helper.h"
36 #include "pfs_buffer_container.h"
37 #include "field.h"
38 #include "xa.h"
39 
40 THR_LOCK table_events_transactions_current::m_table_lock;
41 
42 static const TABLE_FIELD_TYPE field_types[]=
43 {
44   {
45     { C_STRING_WITH_LEN("THREAD_ID") },
46     { C_STRING_WITH_LEN("bigint(20)") },
47     { NULL, 0}
48   },
49   {
50     { C_STRING_WITH_LEN("EVENT_ID") },
51     { C_STRING_WITH_LEN("bigint(20)") },
52     { NULL, 0}
53   },
54   {
55     { C_STRING_WITH_LEN("END_EVENT_ID") },
56     { C_STRING_WITH_LEN("bigint(20)") },
57     { NULL, 0}
58   },
59   {
60     { C_STRING_WITH_LEN("EVENT_NAME") },
61     { C_STRING_WITH_LEN("varchar(128)") },
62     { NULL, 0}
63   },
64   {
65     { C_STRING_WITH_LEN("STATE") },
66     { C_STRING_WITH_LEN("enum(\'ACTIVE\',\'COMMITTED\',\'ROLLED BACK\'") },
67     { NULL, 0}
68   },
69   {
70     { C_STRING_WITH_LEN("TRX_ID") },
71     { C_STRING_WITH_LEN("bigint(20)") },
72     { NULL, 0}
73   },
74   {
75     { C_STRING_WITH_LEN("GTID") },
76     { C_STRING_WITH_LEN("varchar(64)") },
77     { NULL, 0}
78   },
79   {
80     { C_STRING_WITH_LEN("XID_FORMAT_ID") },
81     { C_STRING_WITH_LEN("int(11)") },
82     { NULL, 0}
83   },
84   {
85     { C_STRING_WITH_LEN("XID_GTRID") },
86     { C_STRING_WITH_LEN("varchar(130)") },
87     { NULL, 0}
88   },
89   {
90     { C_STRING_WITH_LEN("XID_BQUAL") },
91     { C_STRING_WITH_LEN("varchar(130)") },
92     { NULL, 0}
93   },
94   {
95     { C_STRING_WITH_LEN("XA_STATE") },
96     { C_STRING_WITH_LEN("varchar(64)") },
97     { NULL, 0}
98   },
99   {
100     { C_STRING_WITH_LEN("SOURCE") },
101     { C_STRING_WITH_LEN("varchar(64)") },
102     { NULL, 0}
103   },
104   {
105     { C_STRING_WITH_LEN("TIMER_START") },
106     { C_STRING_WITH_LEN("bigint(20)") },
107     { NULL, 0}
108   },
109   {
110     { C_STRING_WITH_LEN("TIMER_END") },
111     { C_STRING_WITH_LEN("bigint(20)") },
112     { NULL, 0}
113   },
114   {
115     { C_STRING_WITH_LEN("TIMER_WAIT") },
116     { C_STRING_WITH_LEN("bigint(20)") },
117     { NULL, 0}
118   },
119   {
120     { C_STRING_WITH_LEN("ACCESS_MODE") },
121     { C_STRING_WITH_LEN("enum(\'READ ONLY\',\'READ WRITE\'") },
122     { NULL, 0}
123   },
124   {
125     { C_STRING_WITH_LEN("ISOLATION_LEVEL") },
126     { C_STRING_WITH_LEN("varchar(64)") },
127     { NULL, 0}
128   },
129   {
130     { C_STRING_WITH_LEN("AUTOCOMMIT") },
131     { C_STRING_WITH_LEN("enum(\'YES\',\'NO\'") },
132     { NULL, 0}
133   },
134   {
135     { C_STRING_WITH_LEN("NUMBER_OF_SAVEPOINTS") },
136     { C_STRING_WITH_LEN("bigint(20)") },
137     { NULL, 0}
138   },
139   {
140     { C_STRING_WITH_LEN("NUMBER_OF_ROLLBACK_TO_SAVEPOINT") },
141     { C_STRING_WITH_LEN("bigint(20)") },
142     { NULL, 0}
143   },
144   {
145     { C_STRING_WITH_LEN("NUMBER_OF_RELEASE_SAVEPOINT") },
146     { C_STRING_WITH_LEN("bigint(20)") },
147     { NULL, 0}
148   },
149   {
150     { C_STRING_WITH_LEN("OBJECT_INSTANCE_BEGIN") },
151     { C_STRING_WITH_LEN("bigint") },
152     { NULL, 0}
153   },
154   {
155     { C_STRING_WITH_LEN("NESTING_EVENT_ID") },
156     { C_STRING_WITH_LEN("bigint(20)") },
157     { NULL, 0}
158   },
159   {
160     { C_STRING_WITH_LEN("NESTING_EVENT_TYPE") },
161     { C_STRING_WITH_LEN("enum(\'TRANSACTION\',\'STATEMENT\',\'STAGE\',\'WAIT\'") },
162     { NULL, 0}
163   }
164 };
165 
166 TABLE_FIELD_DEF
167 table_events_transactions_current::m_field_def=
168 {24 , field_types };
169 
170 PFS_engine_table_share
171 table_events_transactions_current::m_share=
172 {
173   { C_STRING_WITH_LEN("events_transactions_current") },
174   &pfs_truncatable_acl,
175   table_events_transactions_current::create,
176   NULL, /* write_row */
177   table_events_transactions_current::delete_all_rows,
178   table_events_transactions_current::get_row_count,
179   sizeof(PFS_simple_index), /* ref length */
180   &m_table_lock,
181   &m_field_def,
182   false, /* checked */
183   false  /* perpetual */
184 };
185 
186 THR_LOCK table_events_transactions_history::m_table_lock;
187 
188 PFS_engine_table_share
189 table_events_transactions_history::m_share=
190 {
191   { C_STRING_WITH_LEN("events_transactions_history") },
192   &pfs_truncatable_acl,
193   table_events_transactions_history::create,
194   NULL, /* write_row */
195   table_events_transactions_history::delete_all_rows,
196   table_events_transactions_history::get_row_count,
197   sizeof(pos_events_transactions_history), /* ref length */
198   &m_table_lock,
199   &table_events_transactions_current::m_field_def,
200   false, /* checked */
201   false  /* perpetual */
202 };
203 
204 THR_LOCK table_events_transactions_history_long::m_table_lock;
205 
206 PFS_engine_table_share
207 table_events_transactions_history_long::m_share=
208 {
209   { C_STRING_WITH_LEN("events_transactions_history_long") },
210   &pfs_truncatable_acl,
211   table_events_transactions_history_long::create,
212   NULL, /* write_row */
213   table_events_transactions_history_long::delete_all_rows,
214   table_events_transactions_history_long::get_row_count,
215   sizeof(PFS_simple_index), /* ref length */
216   &m_table_lock,
217   &table_events_transactions_current::m_field_def,
218   false, /* checked */
219   false  /* perpetual */
220 };
221 
table_events_transactions_common(const PFS_engine_table_share * share,void * pos)222 table_events_transactions_common::table_events_transactions_common
223 (const PFS_engine_table_share *share, void *pos)
224   : PFS_engine_table(share, pos),
225   m_row_exists(false)
226 {}
227 
228 /**
229   Build a row.
230   @param transaction                      the transaction the cursor is reading
231 */
make_row(PFS_events_transactions * transaction)232 void table_events_transactions_common::make_row(PFS_events_transactions *transaction)
233 {
234   ulonglong timer_end;
235 
236   m_row_exists= false;
237 
238   PFS_transaction_class *unsafe= (PFS_transaction_class*) transaction->m_class;
239   PFS_transaction_class *klass= sanitize_transaction_class(unsafe);
240   if (unlikely(klass == NULL))
241     return;
242 
243   m_row.m_thread_internal_id= transaction->m_thread_internal_id;
244   m_row.m_event_id= transaction->m_event_id;
245   m_row.m_end_event_id= transaction->m_end_event_id;
246   m_row.m_nesting_event_id= transaction->m_nesting_event_id;
247   m_row.m_nesting_event_type= transaction->m_nesting_event_type;
248 
249   if (m_row.m_end_event_id == 0)
250   {
251     timer_end= get_timer_raw_value(transaction_timer);
252   }
253   else
254   {
255     timer_end= transaction->m_timer_end;
256   }
257 
258   m_normalizer->to_pico(transaction->m_timer_start, timer_end,
259                         &m_row.m_timer_start, &m_row.m_timer_end, &m_row.m_timer_wait);
260   m_row.m_name= klass->m_name;
261   m_row.m_name_length= klass->m_name_length;
262 
263   /* Disable source file and line to avoid stale __FILE__ pointers. */
264   m_row.m_source_length= 0;
265 
266   /* A GTID consists of the SID (source id) and GNO (transaction number).
267      The SID is stored in transaction->m_sid and the GNO is stored in
268      transaction->m_gtid_spec.gno.
269 
270      On a master, the GTID is assigned when the transaction commit.
271      On a slave, the GTID is assigned before the transaction starts.
272      If GTID_MODE = OFF, all transactions have the special GTID
273      'ANONYMOUS'.
274 
275      Therefore, a transaction can be in three different states wrt GTIDs:
276      - Before the GTID has been assigned, the state is 'AUTOMATIC'.
277        On a master, this is the state until the transaction commits.
278        On a slave, this state does not appear.
279      - If GTID_MODE = ON, and a GTID is assigned, the GTID is a string
280        of the form 'UUID:NUMBER'.
281      - If GTID_MODE = OFF, and a GTID is assigned, the GTID is a string
282        of the form 'ANONYMOUS'.
283 
284      The Gtid_specification contains the GNO, as well as a type code
285      that specifies which of the three modes is currently in effect.
286      Given a SID, it can generate the textual representation of the
287      GTID.
288   */
289   rpl_sid *sid= &transaction->m_sid;
290   Gtid_specification *gtid_spec= &transaction->m_gtid_spec;
291   m_row.m_gtid_length= gtid_spec->to_string(sid, m_row.m_gtid);
292 
293   m_row.m_xid= transaction->m_xid;
294   m_row.m_isolation_level= transaction->m_isolation_level;
295   m_row.m_read_only= transaction->m_read_only;
296   m_row.m_trxid= transaction->m_trxid;
297   m_row.m_state= transaction->m_state;
298   m_row.m_xa_state= transaction->m_xa_state;
299   m_row.m_xa= transaction->m_xa;
300   m_row.m_autocommit= transaction->m_autocommit;
301   m_row.m_savepoint_count= transaction->m_savepoint_count;
302   m_row.m_rollback_to_savepoint_count= transaction->m_rollback_to_savepoint_count;
303   m_row.m_release_savepoint_count= transaction->m_release_savepoint_count;
304   m_row_exists= true;
305   return;
306 }
307 
308 /** Size of XID converted to null-terminated hex string prefixed with 0x. */
309 static const ulong XID_BUFFER_SIZE= XIDDATASIZE*2 + 2 + 1;
310 
311 /**
312   Convert the XID to HEX string prefixed by '0x'
313 
314   @param[out] buf     output hex string buffer, null-terminated
315   @param buf_len size of buffer, must be at least @c XID_BUFFER_SIZE
316   @param xid     XID structure
317   @param offset  offset into XID.data[]
318   @param length  number of bytes to process
319   @return number of bytes in hex string
320 */
xid_to_hex(char * buf,size_t buf_len,PSI_xid * xid,size_t offset,size_t length)321 static uint xid_to_hex(char *buf, size_t buf_len, PSI_xid *xid, size_t offset, size_t length)
322 {
323   assert(buf_len >= XID_BUFFER_SIZE);
324   assert(offset + length <= XIDDATASIZE);
325   *buf++= '0';
326   *buf++= 'x';
327   return bin_to_hex_str(buf, buf_len-2, (char*)(xid->data + offset), length) + 2;
328 }
329 
330 /**
331   Store the XID in printable format if possible, otherwise convert
332   to a string of hex digits.
333 
334   @param  field   Record field
335   @param  xid     XID structure
336   @param  offset  offset into XID.data[]
337   @param  length  number of bytes to process
338 */
xid_store(Field * field,PSI_xid * xid,size_t offset,size_t length)339 static void xid_store(Field *field, PSI_xid *xid, size_t offset, size_t length)
340 {
341   assert(!xid->is_null());
342   if (xid_printable(xid, offset, length))
343   {
344     field->store(xid->data + offset, length, &my_charset_bin);
345   }
346   else
347   {
348     /*
349       xid_buf contains enough space for 0x followed by hex representation of
350       the binary XID data and one null termination character.
351     */
352     char xid_buf[XID_BUFFER_SIZE];
353 
354     size_t xid_str_len= xid_to_hex(xid_buf, sizeof(xid_buf), xid, offset, length);
355     field->store(xid_buf, xid_str_len, &my_charset_bin);
356   }
357 }
358 
xid_store_bqual(Field * field,PSI_xid * xid)359 static void xid_store_bqual(Field *field, PSI_xid *xid)
360 {
361   xid_store(field, xid, xid->gtrid_length, xid->bqual_length);
362 }
363 
xid_store_gtrid(Field * field,PSI_xid * xid)364 static void xid_store_gtrid(Field *field, PSI_xid *xid)
365 {
366   xid_store(field, xid, 0, xid->gtrid_length);
367 }
368 
read_row_values(TABLE * table,unsigned char * buf,Field ** fields,bool read_all)369 int table_events_transactions_common::read_row_values(TABLE *table,
370                                                       unsigned char *buf,
371                                                       Field **fields,
372                                                       bool read_all)
373 {
374   Field *f;
375 
376   if (unlikely(! m_row_exists))
377     return HA_ERR_RECORD_DELETED;
378 
379   /* Set the null bits */
380   assert(table->s->null_bytes == 3);
381   buf[0]= 0;
382   buf[1]= 0;
383   buf[2]= 0;
384 
385   for (; (f= *fields) ; fields++)
386   {
387     if (read_all || bitmap_is_set(table->read_set, f->field_index))
388     {
389       switch(f->field_index)
390       {
391       case 0: /* THREAD_ID */
392         set_field_ulonglong(f, m_row.m_thread_internal_id);
393         break;
394       case 1: /* EVENT_ID */
395         set_field_ulonglong(f, m_row.m_event_id);
396         break;
397       case 2: /* END_EVENT_ID */
398         if (m_row.m_end_event_id > 0)
399           set_field_ulonglong(f, m_row.m_end_event_id - 1);
400         else
401           f->set_null();
402         break;
403       case 3: /* EVENT_NAME */
404         set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length);
405         break;
406       case 4: /* STATE */
407         set_field_enum(f, m_row.m_state);
408         break;
409       case 5: /* TRX_ID */
410         if (m_row.m_trxid != 0)
411           set_field_ulonglong(f, m_row.m_trxid);
412         else
413           f->set_null();
414         break;
415       case 6: /* GTID */
416         set_field_varchar_utf8(f, m_row.m_gtid, m_row.m_gtid_length);
417         break;
418       case 7: /* XID_FORMAT_ID */
419         if (!m_row.m_xa || m_row.m_xid.is_null())
420           f->set_null();
421         else
422           set_field_long(f, m_row.m_xid.formatID);
423         break;
424       case 8: /* XID_GTRID */
425         if (!m_row.m_xa || m_row.m_xid.is_null() || m_row.m_xid.gtrid_length <= 0)
426           f->set_null();
427         else
428           xid_store_gtrid(f, &m_row.m_xid);
429         break;
430       case 9: /* XID_BQUAL */
431         if (!m_row.m_xa || m_row.m_xid.is_null() || m_row.m_xid.bqual_length <= 0)
432           f->set_null();
433         else
434           xid_store_bqual(f, &m_row.m_xid);
435         break;
436       case 10: /* XA STATE */
437         if (!m_row.m_xa || m_row.m_xid.is_null())
438           f->set_null();
439         else
440           set_field_xa_state(f, m_row.m_xa_state);
441         break;
442       case 11: /* SOURCE */
443         set_field_varchar_utf8(f, m_row.m_source, m_row.m_source_length);
444         break;
445       case 12: /* TIMER_START */
446         if (m_row.m_timer_start != 0)
447           set_field_ulonglong(f, m_row.m_timer_start);
448         else
449           f->set_null();
450         break;
451       case 13: /* TIMER_END */
452         if (m_row.m_timer_end != 0)
453           set_field_ulonglong(f, m_row.m_timer_end);
454         else
455           f->set_null();
456         break;
457       case 14: /* TIMER_WAIT */
458         if (m_row.m_timer_wait != 0)
459           set_field_ulonglong(f, m_row.m_timer_wait);
460         else
461           f->set_null();
462         break;
463       case 15: /* ACCESS_MODE */
464         set_field_enum(f, m_row.m_read_only ? TRANS_MODE_READ_ONLY
465                                             : TRANS_MODE_READ_WRITE);
466         break;
467       case 16: /* ISOLATION_LEVEL */
468         set_field_isolation_level(f, m_row.m_isolation_level);
469         break;
470       case 17: /* AUTOCOMMIT */
471         set_field_enum(f, m_row.m_autocommit ? ENUM_YES : ENUM_NO);
472         break;
473       case 18: /* NUMBER_OF_SAVEPOINTS */
474         set_field_ulonglong(f, m_row.m_savepoint_count);
475         break;
476       case 19: /* NUMBER_OF_ROLLBACK_TO_SAVEPOINT */
477         set_field_ulonglong(f, m_row.m_rollback_to_savepoint_count);
478         break;
479       case 20: /* NUMBER_OF_RELEASE_SAVEPOINT */
480         set_field_ulonglong(f, m_row.m_release_savepoint_count);
481         break;
482       case 21: /* OBJECT_INSTANCE_BEGIN */
483         f->set_null();
484         break;
485       case 22: /* NESTING_EVENT_ID */
486         if (m_row.m_nesting_event_id != 0)
487           set_field_ulonglong(f, m_row.m_nesting_event_id);
488         else
489           f->set_null();
490         break;
491       case 23: /* NESTING_EVENT_TYPE */
492         if (m_row.m_nesting_event_id != 0)
493           set_field_enum(f, m_row.m_nesting_event_type);
494         else
495           f->set_null();
496         break;
497       default:
498         assert(false);
499       }
500     }
501   }
502   return 0;
503 }
504 
create(void)505 PFS_engine_table* table_events_transactions_current::create(void)
506 {
507   return new table_events_transactions_current();
508 }
509 
table_events_transactions_current()510 table_events_transactions_current::table_events_transactions_current()
511   : table_events_transactions_common(&m_share, &m_pos),
512   m_pos(0), m_next_pos(0)
513 {}
514 
reset_position(void)515 void table_events_transactions_current::reset_position(void)
516 {
517   m_pos.m_index= 0;
518   m_next_pos.m_index= 0;
519 }
520 
rnd_init(bool scan)521 int table_events_transactions_current::rnd_init(bool scan)
522 {
523   m_normalizer= time_normalizer::get(transaction_timer);
524   return 0;
525 }
526 
rnd_next(void)527 int table_events_transactions_current::rnd_next(void)
528 {
529   PFS_thread *pfs_thread;
530   PFS_events_transactions *transaction;
531   bool has_more_thread= true;
532 
533   for (m_pos.set_at(&m_next_pos);
534        has_more_thread;
535        m_pos.next())
536   {
537     pfs_thread= global_thread_container.get(m_pos.m_index, & has_more_thread);
538     if (pfs_thread != NULL)
539     {
540       transaction= &pfs_thread->m_transaction_current;
541       make_row(transaction);
542       m_next_pos.set_after(&m_pos);
543       return 0;
544     }
545   }
546 
547   return HA_ERR_END_OF_FILE;
548 }
549 
rnd_pos(const void * pos)550 int table_events_transactions_current::rnd_pos(const void *pos)
551 {
552   PFS_thread *pfs_thread;
553   PFS_events_transactions *transaction;
554 
555   set_position(pos);
556 
557   pfs_thread= global_thread_container.get(m_pos.m_index);
558   if (pfs_thread != NULL)
559   {
560     transaction= &pfs_thread->m_transaction_current;
561     if (transaction->m_class != NULL)
562     {
563       make_row(transaction);
564       return 0;
565     }
566   }
567 
568   return HA_ERR_RECORD_DELETED;
569 }
570 
delete_all_rows(void)571 int table_events_transactions_current::delete_all_rows(void)
572 {
573   reset_events_transactions_current();
574   return 0;
575 }
576 
577 ha_rows
get_row_count(void)578 table_events_transactions_current::get_row_count(void)
579 {
580   return global_thread_container.get_row_count();
581 }
582 
create(void)583 PFS_engine_table* table_events_transactions_history::create(void)
584 {
585   return new table_events_transactions_history();
586 }
587 
table_events_transactions_history()588 table_events_transactions_history::table_events_transactions_history()
589   : table_events_transactions_common(&m_share, &m_pos),
590   m_pos(), m_next_pos()
591 {}
592 
reset_position(void)593 void table_events_transactions_history::reset_position(void)
594 {
595   m_pos.reset();
596   m_next_pos.reset();
597 }
598 
rnd_init(bool scan)599 int table_events_transactions_history::rnd_init(bool scan)
600 {
601   m_normalizer= time_normalizer::get(transaction_timer);
602   return 0;
603 }
604 
rnd_next(void)605 int table_events_transactions_history::rnd_next(void)
606 {
607   PFS_thread *pfs_thread;
608   PFS_events_transactions *transaction;
609   bool has_more_thread= true;
610 
611   if (events_transactions_history_per_thread == 0)
612     return HA_ERR_END_OF_FILE;
613 
614   for (m_pos.set_at(&m_next_pos);
615        has_more_thread;
616        m_pos.next_thread())
617   {
618     pfs_thread= global_thread_container.get(m_pos.m_index_1, & has_more_thread);
619     if (pfs_thread != NULL)
620     {
621       if (m_pos.m_index_2 >= events_transactions_history_per_thread)
622       {
623         /* This thread does not have more (full) history */
624         continue;
625       }
626 
627       if ( ! pfs_thread->m_transactions_history_full &&
628           (m_pos.m_index_2 >= pfs_thread->m_transactions_history_index))
629       {
630         /* This thread does not have more (not full) history */
631         continue;
632       }
633 
634       transaction= &pfs_thread->m_transactions_history[m_pos.m_index_2];
635       if (transaction->m_class != NULL)
636       {
637         make_row(transaction);
638         /* Next iteration, look for the next history in this thread */
639         m_next_pos.set_after(&m_pos);
640         return 0;
641       }
642     }
643   }
644 
645   return HA_ERR_END_OF_FILE;
646 }
647 
rnd_pos(const void * pos)648 int table_events_transactions_history::rnd_pos(const void *pos)
649 {
650   PFS_thread *pfs_thread;
651   PFS_events_transactions *transaction;
652 
653   assert(events_transactions_history_per_thread != 0);
654   set_position(pos);
655 
656   assert(m_pos.m_index_2 < events_transactions_history_per_thread);
657 
658   pfs_thread= global_thread_container.get(m_pos.m_index_1);
659   if (pfs_thread != NULL)
660   {
661     if ( ! pfs_thread->m_transactions_history_full &&
662         (m_pos.m_index_2 >= pfs_thread->m_transactions_history_index))
663       return HA_ERR_RECORD_DELETED;
664 
665     transaction= &pfs_thread->m_transactions_history[m_pos.m_index_2];
666     if (transaction->m_class != NULL)
667     {
668       make_row(transaction);
669       return 0;
670     }
671   }
672 
673   return HA_ERR_RECORD_DELETED;
674 }
675 
delete_all_rows(void)676 int table_events_transactions_history::delete_all_rows(void)
677 {
678   reset_events_transactions_history();
679   return 0;
680 }
681 
682 ha_rows
get_row_count(void)683 table_events_transactions_history::get_row_count(void)
684 {
685   return events_transactions_history_per_thread * global_thread_container.get_row_count();
686 }
687 
create(void)688 PFS_engine_table* table_events_transactions_history_long::create(void)
689 {
690   return new table_events_transactions_history_long();
691 }
692 
table_events_transactions_history_long()693 table_events_transactions_history_long::table_events_transactions_history_long()
694   : table_events_transactions_common(&m_share, &m_pos),
695   m_pos(0), m_next_pos(0)
696 {}
697 
reset_position(void)698 void table_events_transactions_history_long::reset_position(void)
699 {
700   m_pos.m_index= 0;
701   m_next_pos.m_index= 0;
702 }
703 
rnd_init(bool scan)704 int table_events_transactions_history_long::rnd_init(bool scan)
705 {
706   m_normalizer= time_normalizer::get(transaction_timer);
707   return 0;
708 }
709 
rnd_next(void)710 int table_events_transactions_history_long::rnd_next(void)
711 {
712   PFS_events_transactions *transaction;
713   uint limit;
714 
715   if (events_transactions_history_long_size == 0)
716     return HA_ERR_END_OF_FILE;
717 
718   if (events_transactions_history_long_full)
719     limit= events_transactions_history_long_size;
720   else
721     limit= events_transactions_history_long_index.m_u32 % events_transactions_history_long_size;
722 
723   for (m_pos.set_at(&m_next_pos); m_pos.m_index < limit; m_pos.next())
724   {
725     transaction= &events_transactions_history_long_array[m_pos.m_index];
726 
727     if (transaction->m_class != NULL)
728     {
729       make_row(transaction);
730       /* Next iteration, look for the next entry */
731       m_next_pos.set_after(&m_pos);
732       return 0;
733     }
734   }
735 
736   return HA_ERR_END_OF_FILE;
737 }
738 
rnd_pos(const void * pos)739 int table_events_transactions_history_long::rnd_pos(const void *pos)
740 {
741   PFS_events_transactions *transaction;
742   uint limit;
743 
744   if (events_transactions_history_long_size == 0)
745     return HA_ERR_RECORD_DELETED;
746 
747   set_position(pos);
748 
749   if (events_transactions_history_long_full)
750     limit= events_transactions_history_long_size;
751   else
752     limit= events_transactions_history_long_index.m_u32 % events_transactions_history_long_size;
753 
754   if (m_pos.m_index >= limit)
755     return HA_ERR_RECORD_DELETED;
756 
757   transaction= &events_transactions_history_long_array[m_pos.m_index];
758 
759   if (transaction->m_class == NULL)
760     return HA_ERR_RECORD_DELETED;
761 
762   make_row(transaction);
763   return 0;
764 }
765 
delete_all_rows(void)766 int table_events_transactions_history_long::delete_all_rows(void)
767 {
768   reset_events_transactions_history_long();
769   return 0;
770 }
771 
772 ha_rows
get_row_count(void)773 table_events_transactions_history_long::get_row_count(void)
774 {
775   return events_transactions_history_long_size;
776 }
777 
778