1 // Copyright 1997-2021 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
LDAPEntriesHandler(TTXlaConnection & conn,const char * ownerP,const char * nameP)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
~LDAPEntriesHandler()99 LDAPEntriesHandler::~LDAPEntriesHandler()
100 {
101
102 }
103
ReverseAndUpper(char * dnP,int id,bool commit)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
HandleInsert(ttXlaUpdateDesc_t * p)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
HandleUpdate(ttXlaUpdateDesc_t * p)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
HandleDelete(ttXlaUpdateDesc_t * p)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
onintr(int sig)206 onintr(int sig)
207 {
208 pleaseStop = 1;
209 cerr << "Stopping...\n";
210 }
211 };
212
213 //----------------------------------------------------------------------
214
215 int
main(int argc,char * argv[])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