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