~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/plugin/event_observer.cc

  • Committer: Stewart Smith
  • Author(s): Marko Mäkelä
  • Date: 2010-12-20 03:21:44 UTC
  • mto: (2021.1.2 build)
  • mto: This revision was merged to the branch mainline in revision 2022.
  • Revision ID: stewart@flamingspork.com-20101220032144-7aqh2z403u7d7bdp
Merge Revision revid:marko.makela@oracle.com-20101104131215-pfxnpidlrzd4krg0 from MySQL InnoDB

Original revid:marko.makela@oracle.com-20101104131215-pfxnpidlrzd4krg0

Original Authors: Marko Mäkelä <marko.makela@oracle.com>
Original commit message:
row_ins_index_entry(): Note that only CREATE INDEX sets foreign=FALSE.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
 
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
3
 *
 
4
 *  Copyright (C) 2010 PrimeBase Technologies GmbH, Germany
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; version 2 of the License.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
18
 *
 
19
 * Barry Leslie
 
20
 *
 
21
 * 2010-05-12
 
22
 */
 
23
 
 
24
#include "config.h"
 
25
 
 
26
#include <string>
 
27
#include <vector>
 
28
 
 
29
#include "drizzled/session.h"
 
30
#include "drizzled/table_list.h"
 
31
#include "drizzled/definition/table.h"
 
32
#include "drizzled/module/registry.h"
 
33
#include "drizzled/plugin/event_observer.h"
 
34
#include <drizzled/util/functors.h>
 
35
#include <algorithm>
 
36
 
 
37
 
 
38
 
 
39
namespace drizzled
 
40
{
 
41
 
 
42
namespace plugin
 
43
{
 
44
 
 
45
/*============================*/
 
46
  // Basic plugin registration stuff.
 
47
  EventObserverVector all_event_plugins;
 
48
 
 
49
  const EventObserverVector &EventObserver::getEventObservers(void)
 
50
  {
 
51
    return all_event_plugins;
 
52
  }
 
53
 
 
54
  //---------
 
55
  bool EventObserver::addPlugin(EventObserver *handler)
 
56
  {
 
57
    if (handler != NULL)
 
58
      all_event_plugins.push_back(handler);
 
59
    return false;
 
60
  }
 
61
 
 
62
  //---------
 
63
  void EventObserver::removePlugin(EventObserver *handler)
 
64
  {
 
65
    if (handler != NULL)
 
66
      all_event_plugins.erase(std::find(all_event_plugins.begin(), all_event_plugins.end(), handler));
 
67
  }
 
68
 
 
69
 
 
70
  /* 
 
71
   * The Event Observer list class in which plugins register which events they
 
72
   * are interested in.
 
73
   *
 
74
   * Each table share for example, will have one of these hung on it to store
 
75
   * a list off all event observers interested in it and which events they are
 
76
   * interested in.
 
77
 */
 
78
  class EventObserverList
 
79
  {
 
80
 
 
81
  public:
 
82
    typedef std::multimap<uint32_t, EventObserver *> ObserverMap;
 
83
 
 
84
  private:
 
85
    /* A list of lists indexed by event type. */
 
86
    std::vector<ObserverMap *> event_observer_lists;
 
87
 
 
88
  public:
 
89
 
 
90
    EventObserverList()
 
91
    {
 
92
                        // Initialize the list with NULL pointers.
 
93
                        event_observer_lists.assign(EventObserver::MAX_EVENT_COUNT, NULL);
 
94
    }
 
95
 
 
96
    ~EventObserverList()
 
97
    {
 
98
      std::for_each(event_observer_lists.begin(),
 
99
                    event_observer_lists.end(),
 
100
                    SafeDeletePtr());
 
101
      event_observer_lists.clear();
 
102
    }
 
103
 
 
104
    /* Add the observer to the observer list for the even, positioning it if required.
 
105
     *
 
106
     * Note: Event observers are storted in a multimap object so that the order in which
 
107
     * they are called can be sorted based on the requested position. Lookups are never done
 
108
     * on the multimap, once filled it is used as a vector.
 
109
   */
 
110
    void addObserver(EventObserver *eventObserver, enum EventObserver::EventType event, int32_t position)
 
111
    {
 
112
      uint32_t event_pos;
 
113
      ObserverMap *observers;
 
114
 
 
115
      observers= event_observer_lists[event];
 
116
      if (observers == NULL) 
 
117
      {
 
118
        observers= new ObserverMap();
 
119
        event_observer_lists[event]= observers;
 
120
      }
 
121
 
 
122
      if (position == 0)
 
123
        event_pos= INT32_MAX; // Set the event position to be in the middle.
 
124
      else
 
125
        event_pos= (uint32_t) position;
 
126
 
 
127
      /* If positioned then check if the position is already taken. */
 
128
      if (position) 
 
129
      {
 
130
        if (observers->find(event_pos) != observers->end())
 
131
        {
 
132
          errmsg_printf(ERRMSG_LVL_WARN,
 
133
                        _("EventObserverList::addEventObserver() Duplicate event position %d for event '%s' from EventObserver plugin '%s'"),
 
134
                        position,
 
135
                        EventObserver::eventName(event), 
 
136
                        eventObserver->getName().c_str());
 
137
        }
 
138
      }
 
139
 
 
140
      observers->insert(std::pair<uint32_t, EventObserver *>(event_pos, eventObserver) );
 
141
    }
 
142
 
 
143
 
 
144
    /* Get the observer list for an event type. Will return NULL if no observer exists.*/
 
145
    ObserverMap *getObservers(enum EventObserver::EventType event)
 
146
    {
 
147
      return event_observer_lists[event];
 
148
    }
 
149
  };
 
150
 
 
151
 
 
152
  //---------
 
153
  /* registerEvent() is called from the event observer plugins to add themselves to
 
154
   * the event observer list to be notified when the specified event takes place.
 
155
   */ 
 
156
  void EventObserver::registerEvent(EventObserverList &observers, EventType event, int32_t position)
 
157
  {
 
158
    observers.addObserver(this, event, position);
 
159
  }
 
160
 
 
161
  /*========================================================*/
 
162
  /*              Table Event Observer handling:           */
 
163
  /*========================================================*/
 
164
 
 
165
  //----------
 
166
  /* For each EventObserver plugin call its registerTableEventsDo() meathod so that it can
 
167
   * register what events, if any, it is interested in on this table.
 
168
   */ 
 
169
  class RegisterTableEventsIterate : public std::unary_function<EventObserver *, void>
 
170
  {
 
171
    TableShare &table_share;
 
172
    EventObserverList &observers;
 
173
 
 
174
  public:
 
175
    RegisterTableEventsIterate(TableShare &table_share_arg, EventObserverList &observers_arg): 
 
176
      table_share(table_share_arg), observers(observers_arg) {}
 
177
    inline result_type operator() (argument_type eventObserver)
 
178
    {
 
179
      eventObserver->registerTableEventsDo(table_share, observers);
 
180
    }
 
181
  };
 
182
 
 
183
  //----------
 
184
  /* 
 
185
   * registerTableEvents() is called by drizzle to register all plugins that
 
186
   * may be interested in table events on the newly created TableShare object.
 
187
   */ 
 
188
  void EventObserver::registerTableEvents(TableShare &table_share)
 
189
  {
 
190
    if (all_event_plugins.empty())
 
191
      return;
 
192
 
 
193
    EventObserverList *observers;
 
194
 
 
195
    observers= table_share.getTableObservers();
 
196
 
 
197
    if (observers != NULL) 
 
198
                {
 
199
                        errmsg_printf(ERRMSG_LVL_WARN,
 
200
                                                                        _("EventObserver::registerTableEvents(): Table already has events registered on it: probable programming error."));
 
201
                        table_share.setTableObservers(NULL);
 
202
      delete observers;
 
203
    }
 
204
 
 
205
                observers= new EventObserverList();
 
206
                table_share.setTableObservers(observers);
 
207
 
 
208
 
 
209
    std::for_each(all_event_plugins.begin(), all_event_plugins.end(),
 
210
                  RegisterTableEventsIterate(table_share, *observers));
 
211
 
 
212
  }
 
213
 
 
214
  //----------
 
215
  /* Cleanup before freeing the TableShare object. */
 
216
  void EventObserver::deregisterTableEvents(TableShare &table_share)
 
217
  {
 
218
   if (all_event_plugins.empty())
 
219
      return;
 
220
 
 
221
    EventObserverList *observers;
 
222
 
 
223
    observers= table_share.getTableObservers();
 
224
 
 
225
    if (observers) 
 
226
    {
 
227
      table_share.setTableObservers(NULL);
 
228
      delete observers;
 
229
    }
 
230
  }
 
231
 
 
232
 
 
233
  /*========================================================*/
 
234
  /*              Schema Event Observer handling:           */
 
235
  /*========================================================*/
 
236
 
 
237
  //----------
 
238
  /* For each EventObserver plugin call its registerSchemaEventsDo() meathod so that it can
 
239
   * register what events, if any, it is interested in on the schema.
 
240
   */ 
 
241
  class RegisterSchemaEventsIterate : public std::unary_function<EventObserver *, void>
 
242
  {
 
243
    const std::string &db;
 
244
    EventObserverList &observers;
 
245
  public:
 
246
    RegisterSchemaEventsIterate(const std::string &db_arg, EventObserverList &observers_arg) :     
 
247
      db(db_arg),
 
248
      observers(observers_arg){}
 
249
 
 
250
    inline result_type operator() (argument_type eventObserver)
 
251
    {
 
252
      eventObserver->registerSchemaEventsDo(db, observers);
 
253
    }
 
254
  };
 
255
 
 
256
  //----------
 
257
  /* 
 
258
   * registerSchemaEvents() is called by drizzle to register all plugins that
 
259
   * may be interested in schema events on the database.
 
260
   */ 
 
261
  void EventObserver::registerSchemaEvents(Session &session, const std::string &db)
 
262
  {
 
263
    if (all_event_plugins.empty())
 
264
      return;
 
265
 
 
266
    EventObserverList *observers;
 
267
 
 
268
    observers= session.getSchemaObservers(db);
 
269
 
 
270
    if (observers == NULL) 
 
271
    {
 
272
      observers= new EventObserverList();
 
273
      session.setSchemaObservers(db, observers);
 
274
   }
 
275
 
 
276
    std::for_each(all_event_plugins.begin(), all_event_plugins.end(),
 
277
                  RegisterSchemaEventsIterate(db, *observers));
 
278
 
 
279
  }
 
280
 
 
281
  //----------
 
282
  /* Cleanup before freeing the Session object. */
 
283
  void EventObserver::deregisterSchemaEvents(Session &session, const std::string &db)
 
284
  {
 
285
    if (all_event_plugins.empty())
 
286
      return;
 
287
 
 
288
    EventObserverList *observers;
 
289
 
 
290
    observers= session.getSchemaObservers(db);
 
291
 
 
292
    if (observers) 
 
293
    {
 
294
      session.setSchemaObservers(db, NULL);
 
295
      delete observers;
 
296
    }
 
297
  }
 
298
 
 
299
  /*========================================================*/
 
300
  /*             Session Event Observer handling:           */
 
301
  /*========================================================*/
 
302
 
 
303
  //----------
 
304
  /* For each EventObserver plugin call its registerSessionEventsDo() meathod so that it can
 
305
   * register what events, if any, it is interested in on this session.
 
306
   */ 
 
307
  class RegisterSessionEventsIterate : public std::unary_function<EventObserver *, void>
 
308
  {
 
309
    Session &session;
 
310
    EventObserverList &observers;
 
311
  public:
 
312
    RegisterSessionEventsIterate(Session &session_arg, EventObserverList &observers_arg) : 
 
313
      session(session_arg), observers(observers_arg) {}
 
314
    inline result_type operator() (argument_type eventObserver)
 
315
    {
 
316
      eventObserver->registerSessionEventsDo(session, observers);
 
317
    }
 
318
  };
 
319
 
 
320
  //----------
 
321
  /* 
 
322
   * registerSessionEvents() is called by drizzle to register all plugins that
 
323
   * may be interested in session events on the newly created session.
 
324
   */ 
 
325
  void EventObserver::registerSessionEvents(Session &session)
 
326
  {
 
327
    if (all_event_plugins.empty())
 
328
      return;
 
329
 
 
330
    EventObserverList *observers;
 
331
 
 
332
    observers= session.getSessionObservers();
 
333
                if (observers) { // This should not happed
 
334
                        errmsg_printf(ERRMSG_LVL_WARN,
 
335
                                                                        _("EventObserver::registerSessionEvents(): Session already has events registered on it: probable programming error."));
 
336
                        session.setSessionObservers(NULL);
 
337
                        delete observers;
 
338
                }
 
339
 
 
340
        observers= new EventObserverList();
 
341
        session.setSessionObservers(observers);
 
342
 
 
343
  std::for_each(all_event_plugins.begin(), all_event_plugins.end(),
 
344
                RegisterSessionEventsIterate(session, *observers));
 
345
 
 
346
  }
 
347
 
 
348
  //----------
 
349
  /* Cleanup before freeing the session object. */
 
350
  void EventObserver::deregisterSessionEvents(Session &session)
 
351
  {
 
352
    if (all_event_plugins.empty())
 
353
      return;
 
354
 
 
355
    EventObserverList *observers;
 
356
 
 
357
    observers= session.getSessionObservers();
 
358
 
 
359
    if (observers) 
 
360
    {
 
361
      session.setSessionObservers(NULL);
 
362
      delete observers;
 
363
    }
 
364
  }
 
365
 
 
366
 
 
367
  /* Event observer list iterator: */
 
368
  //----------
 
369
  class EventIterate : public std::unary_function<std::pair<uint32_t, EventObserver *>, bool>
 
370
  {
 
371
    EventData &data;
 
372
 
 
373
  public:
 
374
    EventIterate(EventData &data_arg) :
 
375
      std::unary_function<std::pair<uint32_t, EventObserver *>, bool>(),
 
376
      data(data_arg)
 
377
    {}
 
378
 
 
379
    inline result_type operator()(argument_type handler)
 
380
    {
 
381
      bool result= handler.second->observeEventDo(data);
 
382
      if (result)
 
383
      {
 
384
        /* TRANSLATORS: The leading word "EventObserver" is the name
 
385
          of the plugin api, and so should not be translated. */
 
386
        errmsg_printf(ERRMSG_LVL_ERROR,
 
387
                      _("EventIterate event handler '%s' failed for event '%s'"),
 
388
                      handler.second->getName().c_str(), handler.second->eventName(data.event));
 
389
 
 
390
      }
 
391
      return result;
 
392
    }
 
393
  };
 
394
 
 
395
 
 
396
  /*==========================================================*/
 
397
  /* Generic meathods called by drizzle to notify all interested  
 
398
   * plugins of an event,
 
399
 */
 
400
 
 
401
  // Call all event observers interested in the event.
 
402
  bool EventData::callEventObservers()
 
403
  {
 
404
    EventObserverList::ObserverMap *eventObservers;
 
405
 
 
406
    if (observerList == NULL)
 
407
      return false; // Nobody was interested in the event. :(
 
408
 
 
409
    eventObservers = observerList->getObservers(event);
 
410
 
 
411
    if (eventObservers == NULL)
 
412
      return false; // Nobody was interested in the event. :(
 
413
 
 
414
    /* Use find_if instead of foreach so that we can collect return codes */
 
415
    EventObserverList::ObserverMap::iterator iter=
 
416
      std::find_if(eventObservers->begin(), eventObservers->end(),
 
417
                   EventIterate(*this)); 
 
418
    /* If iter is == end() here, that means that all of the plugins returned
 
419
     * false, which in this case means they all succeeded. Since we want to 
 
420
     * return false on success, we return the value of the two being !=.
 
421
   */
 
422
    return iter != eventObservers->end();
 
423
  }
 
424
 
 
425
  //--------
 
426
  bool SessionEventData::callEventObservers()
 
427
  {
 
428
    observerList= session.getSessionObservers();
 
429
 
 
430
    return EventData::callEventObservers();
 
431
  }
 
432
 
 
433
  //--------
 
434
  bool SchemaEventData::callEventObservers()
 
435
  {
 
436
    observerList= session.getSchemaObservers(db);
 
437
    if (!observerList) 
 
438
    {
 
439
      EventObserver::registerSchemaEvents(session, db);
 
440
      observerList= session.getSchemaObservers(db);
 
441
    }
 
442
 
 
443
    return EventData::callEventObservers();
 
444
  }
 
445
 
 
446
  //--------
 
447
  bool TableEventData::callEventObservers()
 
448
  {
 
449
    observerList= table.getMutableShare()->getTableObservers();
 
450
 
 
451
    return EventData::callEventObservers();
 
452
  }
 
453
 
 
454
  /*==========================================================*/
 
455
  /* Static meathods called by drizzle to notify interested plugins 
 
456
   * of a schema event.
 
457
 */
 
458
  bool EventObserver::beforeDropTable(Session &session, const drizzled::TableIdentifier &table)
 
459
  {
 
460
    if (all_event_plugins.empty())
 
461
      return false;
 
462
 
 
463
    BeforeDropTableEventData eventData(session, table);
 
464
    return eventData.callEventObservers();
 
465
  }
 
466
 
 
467
  bool EventObserver::afterDropTable(Session &session, const drizzled::TableIdentifier &table, int err)
 
468
  {
 
469
    if (all_event_plugins.empty())
 
470
      return false;
 
471
 
 
472
    AfterDropTableEventData eventData(session, table, err);
 
473
    return eventData.callEventObservers();
 
474
  }
 
475
 
 
476
  bool EventObserver::beforeRenameTable(Session &session, const drizzled::TableIdentifier &from, const drizzled::TableIdentifier &to)
 
477
  {
 
478
    if (all_event_plugins.empty())
 
479
      return false;
 
480
 
 
481
    BeforeRenameTableEventData eventData(session, from, to);
 
482
    return eventData.callEventObservers();
 
483
  }
 
484
 
 
485
  bool EventObserver::afterRenameTable(Session &session, const drizzled::TableIdentifier &from, const drizzled::TableIdentifier &to, int err)
 
486
  {
 
487
    if (all_event_plugins.empty())
 
488
      return false;
 
489
 
 
490
    AfterRenameTableEventData eventData(session, from, to, err);
 
491
    return eventData.callEventObservers();
 
492
  }
 
493
 
 
494
  /*==========================================================*/
 
495
  /* Static meathods called by drizzle to notify interested plugins 
 
496
   * of a table event.
 
497
   *
 
498
   * A quick test is done first to see if there are any interested observers.
 
499
 */
 
500
  bool EventObserver::beforeInsertRecord(Table &table, unsigned char *buf)
 
501
  {
 
502
    if (all_event_plugins.empty() || !TableEventData::hasEvents(table))
 
503
      return false;
 
504
 
 
505
    BeforeInsertRecordEventData eventData(*(table.in_use), table, buf);
 
506
    return eventData.callEventObservers();
 
507
  }
 
508
 
 
509
  bool EventObserver::afterInsertRecord(Table &table, const unsigned char *buf, int err)
 
510
  {
 
511
    if (all_event_plugins.empty() || !TableEventData::hasEvents(table))
 
512
      return false;
 
513
 
 
514
    AfterInsertRecordEventData eventData(*(table.in_use), table, buf, err);
 
515
    return eventData.callEventObservers();
 
516
  }
 
517
 
 
518
  bool EventObserver::beforeDeleteRecord(Table &table, const unsigned char *buf)
 
519
  {
 
520
    if (all_event_plugins.empty() || !TableEventData::hasEvents(table))
 
521
      return false;
 
522
 
 
523
    BeforeDeleteRecordEventData eventData(*(table.in_use), table, buf);
 
524
    return eventData.callEventObservers();
 
525
  }
 
526
 
 
527
  bool EventObserver::afterDeleteRecord(Table &table, const unsigned char *buf, int err)
 
528
  {
 
529
    if (all_event_plugins.empty() || !TableEventData::hasEvents(table))
 
530
      return false;
 
531
 
 
532
    AfterDeleteRecordEventData eventData(*(table.in_use), table, buf, err);
 
533
    return eventData.callEventObservers();
 
534
  }
 
535
 
 
536
  bool EventObserver::beforeUpdateRecord(Table &table, const unsigned char *old_data, unsigned char *new_data)
 
537
  {
 
538
    if (all_event_plugins.empty() || !TableEventData::hasEvents(table))
 
539
      return false;
 
540
 
 
541
    BeforeUpdateRecordEventData eventData(*(table.in_use), table, old_data, new_data);
 
542
    return eventData.callEventObservers();
 
543
  }
 
544
 
 
545
  bool EventObserver::afterUpdateRecord(Table &table, const unsigned char *old_data, unsigned char *new_data, int err)
 
546
  {
 
547
    if (all_event_plugins.empty() || !TableEventData::hasEvents(table))
 
548
      return false;
 
549
 
 
550
    AfterUpdateRecordEventData eventData(*(table.in_use), table, old_data, new_data, err);
 
551
    return eventData.callEventObservers();
 
552
  }
 
553
 
 
554
  /*==========================================================*/
 
555
  /* Static meathods called by drizzle to notify interested plugins 
 
556
   * of a session event.
 
557
   *
 
558
   * A quick test is done first to see if there are any interested observers.
 
559
*/
 
560
  bool EventObserver::beforeCreateDatabase(Session &session, const std::string &db)
 
561
  {
 
562
    if (all_event_plugins.empty() || !SessionEventData::hasEvents(session))
 
563
      return false;
 
564
 
 
565
    BeforeCreateDatabaseEventData eventData(session, db);
 
566
    return eventData.callEventObservers();
 
567
  }
 
568
 
 
569
  bool EventObserver::afterCreateDatabase(Session &session, const std::string &db, int err)
 
570
  {
 
571
    if (all_event_plugins.empty() || !SessionEventData::hasEvents(session))
 
572
      return false;
 
573
 
 
574
    AfterCreateDatabaseEventData eventData(session, db, err);
 
575
    return eventData.callEventObservers();
 
576
  }
 
577
 
 
578
  bool EventObserver::beforeDropDatabase(Session &session, const std::string &db)
 
579
  {
 
580
    if (all_event_plugins.empty() || !SessionEventData::hasEvents(session))
 
581
      return false;
 
582
 
 
583
    BeforeDropDatabaseEventData eventData(session, db);
 
584
    return eventData.callEventObservers();
 
585
  }
 
586
 
 
587
  bool EventObserver::afterDropDatabase(Session &session, const std::string &db, int err)
 
588
  {
 
589
    if (all_event_plugins.empty() || !SessionEventData::hasEvents(session))
 
590
      return false;
 
591
 
 
592
    AfterDropDatabaseEventData eventData(session, db, err);
 
593
    return eventData.callEventObservers();
 
594
  }
 
595
 
 
596
  bool EventObserver::connectSession(Session &session)
 
597
  {
 
598
    if (all_event_plugins.empty() || !SessionEventData::hasEvents(session))
 
599
      return false;
 
600
 
 
601
    ConnectSessionEventData eventData(session);
 
602
    return eventData.callEventObservers();
 
603
  }
 
604
 
 
605
  bool EventObserver::disconnectSession(Session &session)
 
606
  {
 
607
    if (all_event_plugins.empty() || !SessionEventData::hasEvents(session))
 
608
      return false;
 
609
 
 
610
    DisconnectSessionEventData eventData(session);
 
611
    return eventData.callEventObservers();
 
612
  }
 
613
 
 
614
  bool EventObserver::beforeStatement(Session &session)
 
615
  {
 
616
    if (all_event_plugins.empty() || !SessionEventData::hasEvents(session))
 
617
      return false;
 
618
 
 
619
    BeforeStatementEventData eventData(session);
 
620
    return eventData.callEventObservers();
 
621
  }
 
622
 
 
623
  bool EventObserver::afterStatement(Session &session)
 
624
  {
 
625
    if (all_event_plugins.empty() || !SessionEventData::hasEvents(session))
 
626
      return false;
 
627
 
 
628
    AfterStatementEventData eventData(session);
 
629
    return eventData.callEventObservers();
 
630
  }
 
631
 
 
632
 
 
633
} /* namespace plugin */
 
634
} /* namespace drizzled */