mirror of
https://git.openldap.org/openldap/openldap.git
synced 2024-12-27 03:20:22 +08:00
388 lines
8.4 KiB
C++
388 lines
8.4 KiB
C++
// Copyright 1997-2005 The OpenLDAP Foundation, All Rights Reserved.
|
|
// COPYING RESTRICTIONS APPLY, see COPYRIGHT file
|
|
|
|
// (c) Copyright 1999-2001 TimesTen Performance Software. All rights reserved.
|
|
|
|
//// Note: This file was contributed by Sam Drake of TimesTen Performance
|
|
//// Software for use and redistribution as an intregal part of
|
|
//// OpenLDAP Software. -Kdz
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <TTConnectionPool.h>
|
|
#include <TTConnection.h>
|
|
#include <TTCmd.h>
|
|
#include <TTXla.h>
|
|
|
|
#include <signal.h>
|
|
|
|
TTConnectionPool pool;
|
|
TTXlaConnection conn;
|
|
TTConnection conn2;
|
|
TTCmd assignDn_ru;
|
|
TTCmd getNullDNs;
|
|
|
|
//----------------------------------------------------------------------
|
|
// This class contains all the logic to be implemented whenever
|
|
// the SCOTT.MYDATA table is changed. This is the table that is
|
|
// created by "sample.cpp", one of the other TTClasses demos.
|
|
// That application should be executed before this one in order to
|
|
// create and populate the table.
|
|
//----------------------------------------------------------------------
|
|
|
|
class LDAPEntriesHandler: public TTXlaTableHandler {
|
|
private:
|
|
// Definition of the columns in the table
|
|
int Id;
|
|
int Dn;
|
|
int Oc_map_id;
|
|
int Parent;
|
|
int Keyval;
|
|
int Dn_ru;
|
|
|
|
protected:
|
|
|
|
public:
|
|
LDAPEntriesHandler(TTXlaConnection& conn, const char* ownerP, const char* nameP);
|
|
~LDAPEntriesHandler();
|
|
|
|
virtual void HandleDelete(ttXlaUpdateDesc_t*);
|
|
virtual void HandleInsert(ttXlaUpdateDesc_t*);
|
|
virtual void HandleUpdate(ttXlaUpdateDesc_t*);
|
|
|
|
static void ReverseAndUpper(char* dnP, int id, bool commit=true);
|
|
|
|
};
|
|
|
|
LDAPEntriesHandler::LDAPEntriesHandler(TTXlaConnection& conn,
|
|
const char* ownerP, const char* nameP) :
|
|
TTXlaTableHandler(conn, ownerP, nameP)
|
|
{
|
|
Id = Dn = Oc_map_id = Parent = Keyval = Dn_ru = -1;
|
|
|
|
// We are looking for several particular named columns. We need to get
|
|
// the ordinal position of the columns by name for later use.
|
|
|
|
Id = tbl.getColNumber("ID");
|
|
if (Id < 0) {
|
|
cerr << "target table has no 'ID' column" << endl;
|
|
exit(1);
|
|
}
|
|
Dn = tbl.getColNumber("DN");
|
|
if (Dn < 0) {
|
|
cerr << "target table has no 'DN' column" << endl;
|
|
exit(1);
|
|
}
|
|
Oc_map_id = tbl.getColNumber("OC_MAP_ID");
|
|
if (Oc_map_id < 0) {
|
|
cerr << "target table has no 'OC_MAP_ID' column" << endl;
|
|
exit(1);
|
|
}
|
|
Parent = tbl.getColNumber("PARENT");
|
|
if (Parent < 0) {
|
|
cerr << "target table has no 'PARENT' column" << endl;
|
|
exit(1);
|
|
}
|
|
Keyval = tbl.getColNumber("KEYVAL");
|
|
if (Keyval < 0) {
|
|
cerr << "target table has no 'KEYVAL' column" << endl;
|
|
exit(1);
|
|
}
|
|
Dn_ru = tbl.getColNumber("DN_RU");
|
|
if (Dn_ru < 0) {
|
|
cerr << "target table has no 'DN_RU' column" << endl;
|
|
exit(1);
|
|
}
|
|
|
|
}
|
|
|
|
LDAPEntriesHandler::~LDAPEntriesHandler()
|
|
{
|
|
|
|
}
|
|
|
|
void LDAPEntriesHandler::ReverseAndUpper(char* dnP, int id, bool commit)
|
|
{
|
|
TTStatus stat;
|
|
char dn_rn[512];
|
|
int i;
|
|
int j;
|
|
|
|
// Reverse and upper case the given DN
|
|
|
|
for ((j=0, i = strlen(dnP)-1); i > -1; (j++, i--)) {
|
|
dn_rn[j] = toupper(*(dnP+i));
|
|
}
|
|
dn_rn[j] = '\0';
|
|
|
|
|
|
// Update the database
|
|
|
|
try {
|
|
assignDn_ru.setParam(1, (char*) &dn_rn[0]);
|
|
assignDn_ru.setParam(2, id);
|
|
assignDn_ru.Execute(stat);
|
|
}
|
|
catch (TTStatus stat) {
|
|
cerr << "Error updating id " << id << " ('" << dnP << "' to '"
|
|
<< dn_rn << "'): " << stat;
|
|
exit(1);
|
|
}
|
|
|
|
// Commit the transaction
|
|
|
|
if (commit) {
|
|
try {
|
|
conn2.Commit(stat);
|
|
}
|
|
catch (TTStatus stat) {
|
|
cerr << "Error committing update: " << stat;
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LDAPEntriesHandler::HandleInsert(ttXlaUpdateDesc_t* p)
|
|
{
|
|
char* dnP;
|
|
int id;
|
|
|
|
row.Get(Dn, &dnP);
|
|
cerr << "DN '" << dnP << "': Inserted ";
|
|
row.Get(Id, &id);
|
|
|
|
ReverseAndUpper(dnP, id);
|
|
|
|
}
|
|
|
|
void LDAPEntriesHandler::HandleUpdate(ttXlaUpdateDesc_t* p)
|
|
{
|
|
char* newDnP;
|
|
char* oldDnP;
|
|
char oDn[512];
|
|
int id;
|
|
|
|
// row is 'old'; row2 is 'new'
|
|
row.Get(Dn, &oldDnP);
|
|
strcpy(oDn, oldDnP);
|
|
row.Get(Id, &id);
|
|
row2.Get(Dn, &newDnP);
|
|
|
|
cerr << "old DN '" << oDn << "' / new DN '" << newDnP << "' : Updated ";
|
|
|
|
if (strcmp(oDn, newDnP) != 0) {
|
|
// The DN field changed, update it
|
|
cerr << "(new DN: '" << newDnP << "')";
|
|
ReverseAndUpper(newDnP, id);
|
|
}
|
|
else {
|
|
// The DN field did NOT change, leave it alone
|
|
}
|
|
|
|
cerr << endl;
|
|
|
|
}
|
|
|
|
void LDAPEntriesHandler::HandleDelete(ttXlaUpdateDesc_t* p)
|
|
{
|
|
char* dnP;
|
|
|
|
row.Get(Dn, &dnP);
|
|
cerr << "DN '" << dnP << "': Deleted ";
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
int pleaseStop = 0;
|
|
|
|
extern "C" {
|
|
void
|
|
onintr(int sig)
|
|
{
|
|
pleaseStop = 1;
|
|
cerr << "Stopping...\n";
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
int
|
|
main(int argc, char* argv[])
|
|
{
|
|
|
|
char* ownerP;
|
|
|
|
TTXlaTableList list(&conn); // List of tables to monitor
|
|
|
|
// Handlers, one for each table we want to monitor
|
|
|
|
LDAPEntriesHandler* sampP = NULL;
|
|
|
|
// Misc stuff
|
|
|
|
TTStatus stat;
|
|
|
|
ttXlaUpdateDesc_t ** arry;
|
|
|
|
int records;
|
|
|
|
SQLUBIGINT oldsize;
|
|
int j;
|
|
|
|
if (argc < 2) {
|
|
cerr << "syntax: " << argv[0] << " <username>" << endl;
|
|
exit(3);
|
|
}
|
|
|
|
ownerP = argv[1];
|
|
|
|
signal(SIGINT, onintr); /* signal for CTRL-C */
|
|
#ifdef _WIN32
|
|
signal(SIGBREAK, onintr); /* signal for CTRL-BREAK */
|
|
#endif
|
|
|
|
// Before we do anything related to XLA, first we connect
|
|
// to the database. This is the connection we will use
|
|
// to perform non-XLA operations on the tables.
|
|
|
|
try {
|
|
cerr << "Connecting..." << endl;
|
|
|
|
conn2.Connect("DSN=ldap_tt", stat);
|
|
}
|
|
catch (TTStatus stat) {
|
|
cerr << "Error connecting to TimesTen: " << stat;
|
|
exit(1);
|
|
}
|
|
|
|
try {
|
|
assignDn_ru.Prepare(&conn2,
|
|
"update ldap_entries set dn_ru=? where id=?",
|
|
"", stat);
|
|
getNullDNs.Prepare(&conn2,
|
|
"select dn, id from ldap_entries "
|
|
"where dn_ru is null "
|
|
"for update",
|
|
"", stat);
|
|
conn2.Commit(stat);
|
|
}
|
|
catch (TTStatus stat) {
|
|
cerr << "Error preparing update: " << stat;
|
|
exit(1);
|
|
}
|
|
|
|
// If there are any entries with a NULL reversed/upper cased DN,
|
|
// fix them now.
|
|
|
|
try {
|
|
cerr << "Fixing NULL reversed DNs" << endl;
|
|
getNullDNs.Execute(stat);
|
|
for (int k = 0;; k++) {
|
|
getNullDNs.FetchNext(stat);
|
|
if (stat.rc == SQL_NO_DATA_FOUND) break;
|
|
char* dnP;
|
|
int id;
|
|
getNullDNs.getColumn(1, &dnP);
|
|
getNullDNs.getColumn(2, &id);
|
|
// cerr << "Id " << id << ", Dn '" << dnP << "'" << endl;
|
|
LDAPEntriesHandler::ReverseAndUpper(dnP, id, false);
|
|
if (k % 1000 == 0)
|
|
cerr << ".";
|
|
}
|
|
getNullDNs.Close(stat);
|
|
conn2.Commit(stat);
|
|
}
|
|
catch (TTStatus stat) {
|
|
cerr << "Error updating NULL rows: " << stat;
|
|
exit(1);
|
|
}
|
|
|
|
|
|
// Go ahead and start up the change monitoring application
|
|
|
|
cerr << "Starting change monitoring..." << endl;
|
|
try {
|
|
conn.Connect("DSN=ldap_tt", stat);
|
|
}
|
|
catch (TTStatus stat) {
|
|
cerr << "Error connecting to TimesTen: " << stat;
|
|
exit(1);
|
|
}
|
|
|
|
/* set and configure size of buffer */
|
|
conn.setXlaBufferSize((SQLUBIGINT) 1000000, &oldsize, stat);
|
|
if (stat.rc) {
|
|
cerr << "Error setting buffer size " << stat << endl;
|
|
exit(1);
|
|
}
|
|
|
|
// Make a handler to process changes to the MYDATA table and
|
|
// add the handler to the list of all handlers
|
|
|
|
sampP = new LDAPEntriesHandler(conn, ownerP, "ldap_entries");
|
|
if (!sampP) {
|
|
cerr << "Could not create LDAPEntriesHandler" << endl;
|
|
exit(3);
|
|
}
|
|
list.add(sampP);
|
|
|
|
// Enable transaction logging for the table we're interested in
|
|
|
|
sampP->EnableTracking(stat);
|
|
|
|
// Get updates. Dispatch them to the appropriate handler.
|
|
// This loop will handle updates to all the tables.
|
|
|
|
while (pleaseStop == 0) {
|
|
conn.fetchUpdates(&arry, 1000, &records, stat);
|
|
if (stat.rc) {
|
|
cerr << "Error fetching updates" << stat << endl;
|
|
exit(1);
|
|
}
|
|
|
|
// Interpret the updates
|
|
|
|
for(j=0;j < records;j++){
|
|
ttXlaUpdateDesc_t *p;
|
|
|
|
p = arry[j];
|
|
|
|
list.HandleChange(p, stat);
|
|
|
|
} // end for each record fetched
|
|
|
|
if (records) {
|
|
cerr << "Processed " << records << " records\n";
|
|
}
|
|
|
|
if (records == 0) {
|
|
#ifdef _WIN32
|
|
Sleep(250);
|
|
#else
|
|
struct timeval t;
|
|
t.tv_sec = 0;
|
|
t.tv_usec = 250000; // .25 seconds
|
|
select(0, NULL, NULL, NULL, &t);
|
|
#endif
|
|
}
|
|
} // end while pleasestop == 0
|
|
|
|
|
|
// When we get to here, the program is exiting.
|
|
|
|
list.del(sampP); // Take the table out of the list
|
|
delete sampP;
|
|
|
|
conn.setXlaBufferSize(oldsize, NULL, stat);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|