Drizzled Public API Documentation

hello_events.cc

00001 /*
00002  *  Copyright (C) 2010 PrimeBase Technologies GmbH, Germany
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; version 2 of the License.
00007  *
00008  *  This program is distributed in the hope that it will be useful,
00009  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011  *  GNU General Public License for more details.
00012  *
00013  *  You should have received a copy of the GNU General Public License
00014  *  along with this program; if not, write to the Free Software
00015  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00016  *
00017  * Barry Leslie
00018  *
00019  * 2010-05-12
00020  */
00021 
00034 #include <config.h>
00035 #include <string>
00036 #include <cstdio>
00037 #include <boost/program_options.hpp>
00038 #include <drizzled/item.h>
00039 #include <drizzled/module/option_map.h>
00040 #include <drizzled/session.h>
00041 #include <drizzled/table/instance/base.h>
00042 #include "hello_events.h"
00043 
00044 namespace po= boost::program_options;
00045 using namespace drizzled;
00046 using namespace plugin;
00047 using namespace std;
00048 
00049 #define PLUGIN_NAME "hello_events1"
00050 
00051 static bool sysvar_hello_events_enabled;
00052 static HelloEvents *hello_events= NULL;
00053 static string sysvar_db_list;
00054 static string sysvar_table_list;
00055 
00056 /*
00057  * Event observer positions are used to set the order in which
00058  * event observers are called in the case that more than one
00059  * plugin is interested in the same event. You should only specify
00060  * the order if it really matters because if more than one plugin 
00061  * request the same calling position only the first one gets it and
00062  * the others will not be registered for the event. For this reason
00063  * your plugin should always provide a way to reposition the event
00064  * observer to resolve such conflicts.
00065  *
00066  * If position matters you will always initialy ask for the first position (1)
00067  * or the last position (-1) in the calling order, for example it makes no sence 
00068  * to initially ask to be called in position 13.
00069  */
00070 typedef constrained_check<uint64_t, INT32_MAX-1, 1> position_constraint;
00071 typedef constrained_check<int32_t, -1, INT32_MIN+1> post_drop_constraint;
00072 
00073 static position_constraint sysvar_before_write_position;      // Call this event observer first.
00074 static position_constraint sysvar_before_update_position;
00075 static post_drop_constraint sysvar_post_drop_db_position;  // I want my event observer to be called last. No reason, I just do!
00076 
00077 
00078 //==================================
00079 // My table event observers: 
00080 static bool observeBeforeInsertRecord(BeforeInsertRecordEventData &data)
00081 {
00082 
00083   static int count= 0;
00084   count++;
00085   data.session.setVariable("BEFORE_INSERT_RECORD", boost::lexical_cast<std::string>(count));
00086   return false;
00087 }
00088 
00089 //---
00090 static void observeAfterInsertRecord(AfterInsertRecordEventData &data)
00091 {
00092   static int count= 0;
00093   count++;
00094   data.session.setVariable("AFTER_INSERT_RECORD", boost::lexical_cast<std::string>(count));
00095 }
00096 
00097 //---
00098 static bool observeBeforeDeleteRecord(BeforeDeleteRecordEventData &data)
00099 {
00100   static int count= 0;
00101   count++;
00102   data.session.setVariable("AFTER_DELETE_RECORD", boost::lexical_cast<std::string>(count));
00103   return false;
00104 }
00105 
00106 //---
00107 static void observeAfterDeleteRecord(AfterDeleteRecordEventData &data)
00108 {
00109   static int count= 0;
00110   count++;
00111   data.session.setVariable("AFTER_DELETE_RECORD", boost::lexical_cast<std::string>(count));
00112 }
00113 
00114 //---
00115 static bool observeBeforeUpdateRecord(BeforeUpdateRecordEventData &data)
00116 {
00117   static int count= 0;
00118   count++;
00119   data.session.setVariable("BEFORE_UPDATE_RECORD", boost::lexical_cast<std::string>(count));
00120   return false;
00121 }
00122 
00123 //---
00124 static void observeAfterUpdateRecord(AfterUpdateRecordEventData &data)
00125 {
00126   static int count= 0;
00127   count++;
00128   data.session.setVariable("AFTER_UPDATE_RECORD", boost::lexical_cast<std::string>(count));
00129 }
00130 
00131 //==================================
00132 // My schema event observers: 
00133 static void observeAfterDropTable(AfterDropTableEventData &data)
00134 {
00135   static int count= 0;
00136   count++;
00137   data.session.setVariable("AFTER_DROP_TABLE", boost::lexical_cast<std::string>(count));
00138 }
00139 
00140 //---
00141 static void observeAfterRenameTable(AfterRenameTableEventData &data)
00142 {
00143   static int count= 0;
00144   count++;
00145   data.session.setVariable("AFTER_RENAME_TABLE", boost::lexical_cast<std::string>(count));
00146 }
00147 
00148 //---
00149 static void observeAfterCreateDatabase(AfterCreateDatabaseEventData &data)
00150 {
00151   static int count= 0;
00152   count++;
00153   data.session.setVariable("AFTER_CREATE_DATABASE", boost::lexical_cast<std::string>(count));
00154 }
00155 
00156 //---
00157 static void observeAfterDropDatabase(AfterDropDatabaseEventData &data)
00158 {
00159   static int count= 0;
00160   count++;
00161   data.session.setVariable("AFTER_DROP_DATABASE", boost::lexical_cast<std::string>(count));
00162 }
00163 
00164 //---
00165 static void observeConnectSession(ConnectSessionEventData &data)
00166 {
00167   static int count= 0;
00168   count++;
00169   data.session.setVariable("CONNECT_SESSION", boost::lexical_cast<std::string>(count));
00170 }
00171 
00172 //---
00173 static void observeDisconnectSession(DisconnectSessionEventData &data)
00174 {
00175   static int count= 0;
00176   count++;
00177   data.session.setVariable("DISCONNECT_SESSION", boost::lexical_cast<std::string>(count));
00178 }
00179 
00180 //---
00181 static void observeBeforeStatement(BeforeStatementEventData &data)
00182 {
00183   static int count= 0;
00184   count++;
00185   data.session.setVariable("BEFORE_STATEMENT", boost::lexical_cast<std::string>(count));
00186 }
00187 
00188 //---
00189 static void observeAfterStatement(AfterStatementEventData &data)
00190 {
00191   static int count= 0;
00192   count++;
00193   data.session.setVariable("AFTER_STATEMENT", boost::lexical_cast<std::string>(count));
00194 }
00195 
00196 HelloEvents::~HelloEvents()
00197 { }
00198 
00199 //==================================
00200 /* This is where I register which table events my pluggin is interested in.*/
00201 void HelloEvents::registerTableEventsDo(TableShare &table_share, EventObserverList &observers)
00202 {
00203   if ((is_enabled == false) 
00204     || !isTableInteresting(table_share.getTableName())
00205     || !isDatabaseInteresting(table_share.getSchemaName()))
00206     return;
00207     
00208   registerEvent(observers, BEFORE_INSERT_RECORD, sysvar_before_write_position.get());
00209   // I want to be called first if passible
00210   registerEvent(observers, AFTER_INSERT_RECORD);
00211   registerEvent(observers, BEFORE_UPDATE_RECORD, sysvar_before_update_position.get());
00212   registerEvent(observers, AFTER_UPDATE_RECORD);
00213   registerEvent(observers, BEFORE_DELETE_RECORD);
00214   registerEvent(observers, AFTER_DELETE_RECORD);
00215 }
00216 
00217 //==================================
00218 /* This is where I register which schema events my pluggin is interested in.*/
00219 void HelloEvents::registerSchemaEventsDo(const std::string &db, EventObserverList &observers)
00220 {
00221   if ((is_enabled == false) 
00222     || !isDatabaseInteresting(db))
00223     return;
00224     
00225   registerEvent(observers, AFTER_DROP_TABLE);
00226   registerEvent(observers, AFTER_RENAME_TABLE);
00227 }
00228 
00229 //==================================
00230 /* This is where I register which session events my pluggin is interested in.*/
00231 void HelloEvents::registerSessionEventsDo(Session &session, EventObserverList &observers)
00232 {
00233   if ((is_enabled == false) 
00234     || !isSessionInteresting(session))
00235     return;
00236     
00237   registerEvent(observers, AFTER_CREATE_DATABASE);
00238   registerEvent(observers, AFTER_DROP_DATABASE, sysvar_post_drop_db_position.get());
00239   registerEvent(observers, DISCONNECT_SESSION);
00240   registerEvent(observers, CONNECT_SESSION);
00241   registerEvent(observers, BEFORE_STATEMENT);
00242   registerEvent(observers, AFTER_STATEMENT);
00243 }
00244 
00245 
00246 //==================================
00247 /* The event observer.*/
00248 bool HelloEvents::observeEventDo(EventData &data)
00249 {
00250   bool result= false;
00251   
00252   switch (data.event) {
00253   case AFTER_DROP_TABLE:
00254     observeAfterDropTable((AfterDropTableEventData &)data);
00255     break;
00256     
00257   case AFTER_RENAME_TABLE:
00258     observeAfterRenameTable((AfterRenameTableEventData &)data);
00259     break;
00260     
00261   case BEFORE_INSERT_RECORD:
00262      result = observeBeforeInsertRecord((BeforeInsertRecordEventData &)data);
00263     break;
00264     
00265   case AFTER_INSERT_RECORD:
00266     observeAfterInsertRecord((AfterInsertRecordEventData &)data);
00267     break;     
00268        
00269   case BEFORE_UPDATE_RECORD:
00270     result = observeBeforeUpdateRecord((BeforeUpdateRecordEventData &)data);
00271     break;
00272              
00273   case AFTER_UPDATE_RECORD:
00274      observeAfterUpdateRecord((AfterUpdateRecordEventData &)data);
00275     break;     
00276     
00277   case BEFORE_DELETE_RECORD:
00278     result = observeBeforeDeleteRecord((BeforeDeleteRecordEventData &)data);
00279     break;
00280 
00281   case AFTER_DELETE_RECORD:
00282     observeAfterDeleteRecord((AfterDeleteRecordEventData &)data);
00283     break;
00284 
00285   case AFTER_CREATE_DATABASE:
00286     observeAfterCreateDatabase((AfterCreateDatabaseEventData &)data);
00287     break;
00288 
00289   case AFTER_DROP_DATABASE:
00290     observeAfterDropDatabase((AfterDropDatabaseEventData &)data);
00291     break;
00292 
00293   case CONNECT_SESSION:
00294     observeConnectSession((ConnectSessionEventData &)data);
00295     break;
00296 
00297   case DISCONNECT_SESSION:
00298     observeDisconnectSession((DisconnectSessionEventData &)data);
00299     break;
00300 
00301   case BEFORE_STATEMENT:
00302     observeBeforeStatement((BeforeStatementEventData &)data);
00303     break;
00304 
00305   case AFTER_STATEMENT:
00306     observeAfterStatement((AfterStatementEventData &)data);
00307     break;
00308 
00309   default:
00310     fprintf(stderr, "HelloEvents: Unexpected event '%s'\n", EventObserver::eventName(data.event));
00311  
00312   }
00313   
00314   return false;
00315 }
00316 
00317 //==================================
00318 // Some custom things for my plugin:
00319 
00320 
00321 /* Plugin initialization and system variables */
00322 
00323 static void enable(Session*, sql_var_t)
00324 {
00325   if (hello_events)
00326   {
00327     if (sysvar_hello_events_enabled)
00328     {
00329       hello_events->enable();
00330     }
00331     else
00332     {
00333       hello_events->disable();
00334     }
00335   }
00336 }
00337 
00338 
00339 static int set_db_list(Session *, set_var *var)
00340 {
00341   const char *db_list= var->value->str_value.ptr();
00342   if (db_list == NULL)
00343     return 1;
00344 
00345   if (hello_events)
00346   {
00347     hello_events->setDatabasesOfInterest(db_list);
00348     sysvar_db_list.assign(db_list);
00349   }
00350   return 0;
00351 }
00352 
00353 static int set_table_list(Session *, set_var *var)
00354 {
00355   const char *table_list= var->value->str_value.ptr();
00356   if (table_list == NULL)
00357     return 1;
00358 
00359   if (hello_events)
00360   {
00361     hello_events->setTablesOfInterest(table_list);
00362     sysvar_table_list.assign(table_list);
00363   }
00364   return 0;
00365 }
00366 
00367 
00368 static int init(module::Context &context)
00369 {
00370   hello_events= new HelloEvents(PLUGIN_NAME);
00371 
00372   context.add(hello_events);
00373 
00374   if (sysvar_hello_events_enabled)
00375   {
00376     hello_events->enable();
00377   }
00378 
00379   context.registerVariable(new sys_var_bool_ptr("enable",
00380                                                 &sysvar_hello_events_enabled,
00381                                                 enable));
00382   context.registerVariable(new sys_var_std_string("watch_databases",
00383                                                   sysvar_db_list,
00384                                                   set_db_list));
00385   context.registerVariable(new sys_var_std_string("watch_tables",
00386                                                   sysvar_table_list,
00387                                                   set_table_list));
00388   context.registerVariable(new sys_var_constrained_value<uint64_t>("before_write_position",
00389                                                          sysvar_before_write_position));
00390   context.registerVariable(new sys_var_constrained_value<uint64_t>("before_update_position",
00391                                                          sysvar_before_update_position));
00392   context.registerVariable(new sys_var_constrained_value<int32_t>("post_drop_position",
00393                                                          sysvar_post_drop_db_position));
00394 
00395 
00396   return 0;
00397 }
00398 
00399 static void init_options(drizzled::module::option_context &context)
00400 {
00401   context("enable",
00402           po::value<bool>(&sysvar_hello_events_enabled)->default_value(false)->zero_tokens(),
00403           N_("Enable Example Events Plugin"));
00404   context("watch-databases",
00405           po::value<string>(&sysvar_db_list)->default_value(""),
00406           N_("A comma delimited list of databases to watch"));
00407   context("watch-tables",
00408           po::value<string>(&sysvar_table_list)->default_value(""),
00409           N_("A comma delimited list of databases to watch"));
00410   context("before-write-position",
00411           po::value<position_constraint>(&sysvar_before_write_position)->default_value(1),
00412           N_("Before write row event observer call position"));
00413   context("before-update-position",
00414           po::value<position_constraint>(&sysvar_before_update_position)->default_value(1),
00415           N_("Before update row event observer call position"));
00416   context("post-drop-db-position",
00417           po::value<post_drop_constraint>(&sysvar_post_drop_db_position)->default_value(-1),
00418           N_("After drop database event observer call position"));
00419 }
00420 
00421 
00422 
00423 DRIZZLE_DECLARE_PLUGIN
00424 {
00425   DRIZZLE_VERSION_ID,
00426   PLUGIN_NAME,
00427   "0.1",
00428   "Barry Leslie",
00429   N_("An example events Plugin"),
00430   PLUGIN_LICENSE_BSD,
00431   init,   /* Plugin Init      */
00432   NULL, /* depends */
00433   init_options    /* config options   */
00434 }
00435 DRIZZLE_DECLARE_PLUGIN_END;