Home | History | Annotate | Line # | Download | only in dnreverse
      1 // Copyright 1997-2024 The OpenLDAP Foundation, All Rights Reserved.
      2 //  COPYING RESTRICTIONS APPLY, see COPYRIGHT file
      3 
      4 // (c) Copyright 1999-2001 TimesTen Performance Software. All rights reserved.
      5 
      6 //// Note: This file was contributed by Sam Drake of TimesTen Performance
      7 ////       Software for use and redistribution as an integral part of
      8 ////       OpenLDAP Software.  -Kdz
      9 
     10 #include <stdlib.h>
     11 
     12 #include <TTConnectionPool.h>
     13 #include <TTConnection.h>
     14 #include <TTCmd.h>
     15 #include <TTXla.h>
     16 
     17 #include <signal.h>
     18 
     19 TTConnectionPool pool;
     20 TTXlaConnection  conn;
     21 TTConnection     conn2;
     22 TTCmd            assignDn_ru;
     23 TTCmd            getNullDNs;
     24 
     25 //----------------------------------------------------------------------
     26 // This class contains all the logic to be implemented whenever
     27 // the SCOTT.MYDATA table is changed.  This is the table that is
     28 // created by "sample.cpp", one of the other TTClasses demos.
     29 // That application should be executed before this one in order to
     30 // create and populate the table.
     31 //----------------------------------------------------------------------
     32 
     33 class LDAPEntriesHandler: public TTXlaTableHandler {
     34 private:
     35   // Definition of the columns in the table
     36   int Id;
     37   int Dn;
     38   int Oc_map_id;
     39   int Parent;
     40   int Keyval;
     41   int Dn_ru;
     42 
     43 protected:
     44 
     45 public:
     46   LDAPEntriesHandler(TTXlaConnection& conn, const char* ownerP, const char* nameP);
     47   ~LDAPEntriesHandler();
     48 
     49   virtual void HandleDelete(ttXlaUpdateDesc_t*);
     50   virtual void HandleInsert(ttXlaUpdateDesc_t*);
     51   virtual void HandleUpdate(ttXlaUpdateDesc_t*);
     52 
     53   static void ReverseAndUpper(char* dnP, int id, bool commit=true);
     54 
     55 };
     56 
     57 LDAPEntriesHandler::LDAPEntriesHandler(TTXlaConnection& conn,
     58 				       const char* ownerP, const char* nameP) :
     59   TTXlaTableHandler(conn, ownerP, nameP)
     60 {
     61   Id = Dn = Oc_map_id = Parent = Keyval = Dn_ru = -1;
     62 
     63   // We are looking for several particular named columns.  We need to get
     64   // the ordinal position of the columns by name for later use.
     65 
     66   Id = tbl.getColNumber("ID");
     67   if (Id < 0) {
     68     cerr << "target table has no 'ID' column" << endl;
     69     exit(1);
     70   }
     71   Dn = tbl.getColNumber("DN");
     72   if (Dn < 0) {
     73     cerr << "target table has no 'DN' column" << endl;
     74     exit(1);
     75   }
     76   Oc_map_id = tbl.getColNumber("OC_MAP_ID");
     77   if (Oc_map_id < 0) {
     78     cerr << "target table has no 'OC_MAP_ID' column" << endl;
     79     exit(1);
     80   }
     81   Parent = tbl.getColNumber("PARENT");
     82   if (Parent < 0) {
     83     cerr << "target table has no 'PARENT' column" << endl;
     84     exit(1);
     85   }
     86   Keyval = tbl.getColNumber("KEYVAL");
     87   if (Keyval < 0) {
     88     cerr << "target table has no 'KEYVAL' column" << endl;
     89     exit(1);
     90   }
     91   Dn_ru = tbl.getColNumber("DN_RU");
     92   if (Dn_ru < 0) {
     93     cerr << "target table has no 'DN_RU' column" << endl;
     94     exit(1);
     95   }
     96 
     97 }
     98 
     99 LDAPEntriesHandler::~LDAPEntriesHandler()
    100 {
    101 
    102 }
    103 
    104 void LDAPEntriesHandler::ReverseAndUpper(char* dnP, int id, bool commit)
    105 {
    106   TTStatus stat;
    107   char dn_rn[512];
    108   int i;
    109   int j;
    110 
    111   // Reverse and upper case the given DN
    112 
    113   for ((j=0, i = strlen(dnP)-1); i > -1; (j++, i--)) {
    114     dn_rn[j] = toupper(*(dnP+i));
    115   }
    116   dn_rn[j] = '\0';
    117 
    118 
    119   // Update the database
    120 
    121   try {
    122     assignDn_ru.setParam(1, (char*) &dn_rn[0]);
    123     assignDn_ru.setParam(2, id);
    124     assignDn_ru.Execute(stat);
    125   }
    126   catch (TTStatus stat) {
    127     cerr << "Error updating id " << id << " ('" << dnP << "' to '"
    128 	 << dn_rn << "'): " << stat;
    129     exit(1);
    130   }
    131 
    132   // Commit the transaction
    133 
    134   if (commit) {
    135     try {
    136       conn2.Commit(stat);
    137     }
    138     catch (TTStatus stat) {
    139       cerr << "Error committing update: " << stat;
    140       exit(1);
    141     }
    142   }
    143 
    144 }
    145 
    146 
    147 
    148 void LDAPEntriesHandler::HandleInsert(ttXlaUpdateDesc_t* p)
    149 {
    150   char* dnP;
    151   int   id;
    152 
    153   row.Get(Dn, &dnP);
    154   cerr << "DN '" << dnP << "': Inserted ";
    155   row.Get(Id, &id);
    156 
    157   ReverseAndUpper(dnP, id);
    158 
    159 }
    160 
    161 void LDAPEntriesHandler::HandleUpdate(ttXlaUpdateDesc_t* p)
    162 {
    163   char* newDnP;
    164   char* oldDnP;
    165   char  oDn[512];
    166   int   id;
    167 
    168   // row is 'old'; row2 is 'new'
    169   row.Get(Dn, &oldDnP);
    170   strcpy(oDn, oldDnP);
    171   row.Get(Id, &id);
    172   row2.Get(Dn, &newDnP);
    173 
    174   cerr << "old DN '" << oDn << "' / new DN '" << newDnP << "' : Updated ";
    175 
    176   if (strcmp(oDn, newDnP) != 0) {
    177     // The DN field changed, update it
    178     cerr << "(new DN: '" << newDnP << "')";
    179     ReverseAndUpper(newDnP, id);
    180   }
    181   else {
    182     // The DN field did NOT change, leave it alone
    183   }
    184 
    185   cerr << endl;
    186 
    187 }
    188 
    189 void LDAPEntriesHandler::HandleDelete(ttXlaUpdateDesc_t* p)
    190 {
    191   char* dnP;
    192 
    193   row.Get(Dn, &dnP);
    194   cerr << "DN '" << dnP << "': Deleted ";
    195 }
    196 
    197 
    198 
    199 
    200 //----------------------------------------------------------------------
    201 
    202 int pleaseStop = 0;
    203 
    204 extern "C" {
    205   void
    206   onintr(int sig)
    207   {
    208     pleaseStop = 1;
    209     cerr << "Stopping...\n";
    210   }
    211 };
    212 
    213 //----------------------------------------------------------------------
    214 
    215 int
    216 main(int argc, char* argv[])
    217 {
    218 
    219   char* ownerP;
    220 
    221   TTXlaTableList list(&conn);	// List of tables to monitor
    222 
    223   // Handlers, one for each table we want to monitor
    224 
    225   LDAPEntriesHandler* sampP = NULL;
    226 
    227   // Misc stuff
    228 
    229   TTStatus stat;
    230 
    231   ttXlaUpdateDesc_t ** arry;
    232 
    233   int records;
    234 
    235   SQLUBIGINT  oldsize;
    236   int j;
    237 
    238   if (argc < 2) {
    239     cerr << "syntax: " << argv[0] << " <username>" << endl;
    240     exit(3);
    241   }
    242 
    243   ownerP = argv[1];
    244 
    245   signal(SIGINT, onintr);    /* signal for CTRL-C */
    246 #ifdef _WIN32
    247   signal(SIGBREAK, onintr);  /* signal for CTRL-BREAK */
    248 #endif
    249 
    250   // Before we do anything related to XLA, first we connect
    251   // to the database.  This is the connection we will use
    252   // to perform non-XLA operations on the tables.
    253 
    254   try {
    255     cerr << "Connecting..." << endl;
    256 
    257     conn2.Connect("DSN=ldap_tt", stat);
    258   }
    259   catch (TTStatus stat) {
    260     cerr << "Error connecting to TimesTen: " << stat;
    261     exit(1);
    262   }
    263 
    264   try {
    265     assignDn_ru.Prepare(&conn2,
    266 			"update ldap_entries set dn_ru=? where id=?",
    267 			"", stat);
    268     getNullDNs.Prepare(&conn2,
    269 		       "select dn, id from ldap_entries "
    270 			"where dn_ru is null "
    271 			"for update",
    272 		       "", stat);
    273     conn2.Commit(stat);
    274   }
    275   catch (TTStatus stat) {
    276     cerr << "Error preparing update: " << stat;
    277     exit(1);
    278   }
    279 
    280   // If there are any entries with a NULL reversed/upper cased DN,
    281   // fix them now.
    282 
    283   try {
    284     cerr << "Fixing NULL reversed DNs" << endl;
    285     getNullDNs.Execute(stat);
    286     for (int k = 0;; k++) {
    287       getNullDNs.FetchNext(stat);
    288       if (stat.rc == SQL_NO_DATA_FOUND) break;
    289       char* dnP;
    290       int   id;
    291       getNullDNs.getColumn(1, &dnP);
    292       getNullDNs.getColumn(2, &id);
    293       // cerr << "Id " << id << ", Dn '" << dnP << "'" << endl;
    294       LDAPEntriesHandler::ReverseAndUpper(dnP, id, false);
    295       if (k % 1000 == 0)
    296         cerr << ".";
    297     }
    298     getNullDNs.Close(stat);
    299     conn2.Commit(stat);
    300   }
    301   catch (TTStatus stat) {
    302     cerr << "Error updating NULL rows: " << stat;
    303     exit(1);
    304   }
    305 
    306 
    307   // Go ahead and start up the change monitoring application
    308 
    309   cerr << "Starting change monitoring..." << endl;
    310   try {
    311     conn.Connect("DSN=ldap_tt", stat);
    312   }
    313   catch (TTStatus stat) {
    314     cerr << "Error connecting to TimesTen: " << stat;
    315     exit(1);
    316   }
    317 
    318   /* set and configure size of buffer */
    319   conn.setXlaBufferSize((SQLUBIGINT) 1000000, &oldsize, stat);
    320   if (stat.rc) {
    321     cerr << "Error setting buffer size " << stat << endl;
    322     exit(1);
    323   }
    324 
    325   // Make a handler to process changes to the MYDATA table and
    326   // add the handler to the list of all handlers
    327 
    328   sampP = new LDAPEntriesHandler(conn, ownerP, "ldap_entries");
    329   if (!sampP) {
    330     cerr << "Could not create LDAPEntriesHandler" << endl;
    331     exit(3);
    332   }
    333   list.add(sampP);
    334 
    335   // Enable transaction logging for the table we're interested in
    336 
    337   sampP->EnableTracking(stat);
    338 
    339   // Get updates.  Dispatch them to the appropriate handler.
    340   // This loop will handle updates to all the tables.
    341 
    342   while (pleaseStop == 0) {
    343     conn.fetchUpdates(&arry, 1000, &records, stat);
    344     if (stat.rc) {
    345       cerr << "Error fetching updates" << stat << endl;
    346       exit(1);
    347     }
    348 
    349     // Interpret the updates
    350 
    351     for(j=0;j < records;j++){
    352       ttXlaUpdateDesc_t *p;
    353 
    354       p = arry[j];
    355 
    356       list.HandleChange(p, stat);
    357 
    358     } // end for each record fetched
    359 
    360     if (records) {
    361       cerr << "Processed " << records << " records\n";
    362     }
    363 
    364     if (records == 0) {
    365 #ifdef _WIN32
    366       Sleep(250);
    367 #else
    368       struct timeval t;
    369       t.tv_sec = 0;
    370       t.tv_usec = 250000; // .25 seconds
    371       select(0, NULL, NULL, NULL, &t);
    372 #endif
    373     }
    374   } // end while pleasestop == 0
    375 
    376 
    377   // When we get to here, the program is exiting.
    378 
    379   list.del(sampP);		// Take the table out of the list
    380   delete sampP;
    381 
    382   conn.setXlaBufferSize(oldsize, NULL, stat);
    383 
    384   return 0;
    385 
    386 }
    387 
    388