modules/ud/ud_comrol.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- rollback
- commit
- delete
1 /***************************************
2 $Revision: 1.13 $
3
4 rollback(), commit(), delete() - rollback, commit update transaction, delete an object
5
6 Status: NOT REVUED, NOT TESTED
7
8 Author(s): Andrei Robachevsky
9
10 ******************/ /******************
11 Modification History:
12 andrei (17/01/2000) Created.
13 ******************/ /******************
14 Copyright (c) 2000 RIPE NCC
15
16 All Rights Reserved
17
18 Permission to use, copy, modify, and distribute this software and its
19 documentation for any purpose and without fee is hereby granted,
20 provided that the above copyright notice appear in all copies and that
21 both that copyright notice and this permission notice appear in
22 supporting documentation, and that the name of the author not be
23 used in advertising or publicity pertaining to distribution of the
24 software without specific, written prior permission.
25
26 THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
27 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
28 AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
29 DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
30 AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
31 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
32 ***************************************/
33 #include "ud.h"
34 #include "ud_int.h"
35 #include "ud_comrol.h"
36 #include "rp.h"
37
38 #define RIPE_REG 17
39
40 /************************************************************
41 * int rollback(Transaction_t *tr)
42 * Rollback the transaction
43 *
44 * **********************************************************/
45 int rollback(Transaction_t *tr) {
/* [<][>][^][v][top][bottom][index][help] */
46 GString *query;
47 long sequence_id;
48 int i, j;
49 int sql_err;
50
51 if(ACT_DELETE(tr->action)) return(0);
52
53 if ((query = g_string_sized_new(STR_XXL)) == NULL){
54 fprintf(stderr, "E: cannot allocate gstring\n");
55 tr->succeeded=0;
56 tr->error |= ERROR_U_MEM;
57 return(ERROR_U_MEM); }
58
59 /* Lock all relevant tables */
60 g_string_sprintf(query, "LOCK TABLES %s WRITE,", DF_get_class_sql_table(tr->class_type));
61
62 for (i=0; tables[tr->class_type][i] != NULL; i++)
63 g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
64
65 for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
66 g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
67
68 g_string_sprintfa(query, " last WRITE, history WRITE ");
69
70 sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
71
72 /*fprintf(stderr,"%s\n", query->str);*/
73
74
75 /* Process AUX and LEAF tables */
76 for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
77 /* Delete what has been inserted */
78 g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld AND thread_id=%d", tables[tr->class_type][i], tr->object_id, tr->thread_ins);
79 sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
80
81 /* Normalize what has been updated/touched */
82 g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld AND thread_id=%d", tables[tr->class_type][i], tr->object_id, tr->thread_upd);
83 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
84 }
85
86 /* Process MAIN tables */
87 g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld AND thread_id=%d",
88 DF_get_class_sql_table(tr->class_type), tr->object_id, tr->thread_ins);
89 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
90
91 /* This is needed only for objects with dummies, as they are updated with TR_UPDATE */
92 /* We use this tag when commiting the update to set dummy==0 */
93 /* XXX may be later this should be reconsidered */
94 g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld AND thread_id=%d",
95 DF_get_class_sql_table(tr->class_type), tr->object_id, tr->thread_upd);
96 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
97
98 /* Now tables that might be affected by dummies */
99 for(j=0; j < tr->ndummy; j++)
100 for (i=0; tables[tr->class_type][i] != NULL; i++) {
101 g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", tables[tr->class_type][i], tr->dummy_id[j]);
102 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
103 }
104
105 /* Rollback last and history tables */
106 if(ACT_UPDATE(tr->action)) { /* so we are updating an object */
107 g_string_sprintf(query, "DELETE FROM history WHERE object_id=%ld AND sequence_id=%ld", tr->object_id, tr->sequence_id-1);
108 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
109 /* we do not need to delete a row in the last for updates */
110 }
111 else { /* we failed to create an object */
112 sequence_id=1; /* sequence start == 1 */
113 g_string_sprintf(query, "DELETE FROM last WHERE object_id=%ld AND sequence_id=%ld", tr->object_id, sequence_id);
114 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
115 }
116
117
118 for(j=0; j < tr->ndummy; j++){/* if dummies have been created */
119 g_string_sprintf(query, "DELETE FROM last WHERE object_id=%ld ", tr->dummy_id[j]);
120 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
121 }
122
123 /* Unlock all tables */
124 g_string_sprintf(query, "UNLOCK TABLES ");
125 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
126
127
128 g_string_free(query, TRUE);
129 return(0);
130 } /* rollback() */
131
132 /************************************************************
133 * int commit(Transaction_t *tr)
134 * Commit the transaction
135 *
136 * **********************************************************/
137 int commit(Transaction_t *tr) {
/* [<][>][^][v][top][bottom][index][help] */
138 GString *query;
139 int err=0;
140 int i,j;
141 A_Type_t attr_type;
142 int sql_err;
143
144 if(ACT_DELETE(tr->action)) return(0);
145
146 if ((query = g_string_sized_new(STR_XXL)) == NULL){
147 fprintf(stderr, "E: cannot allocate gstring\n");
148 tr->succeeded=0;
149 tr->error|=ERROR_U_MEM;
150 return(ERROR_U_MEM);
151 }
152
153 /* Lock all relevant tables */
154 g_string_sprintf(query, "LOCK TABLES %s WRITE,", DF_get_class_sql_table(tr->class_type));
155
156 for (i=0; tables[tr->class_type][i] != NULL; i++)
157 g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
158
159 for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
160 g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
161
162 g_string_sprintfa(query, " last WRITE, history WRITE ");
163
164 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
165
166 /* fprintf(stderr,"%s\n", query->str); */
167
168 /* Commit the transaction for AUX and LEAF tables that may be affected (taken from object template) */
169 for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
170 /* Delete old records from the tables */
171 g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld AND thread_id=0 ", tables[tr->class_type][i], tr->object_id);
172 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
173 /* fprintf(stderr, "D: query (del old): %s\n", query->str); */
174
175 /* Set thread_id to 0 to commit the transaction */
176 g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld", tables[tr->class_type][i], tr->object_id);
177 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
178 /* fprintf(stderr, "D: query (com new): %s\n", query->str); */
179 }
180
181 /* Commit the transaction for the MAIN tables */
182
183 /* Commit the transaction for person_role, mntner, as_set, route_set tables */
184 /* They require different handling because of dummies */
185 /* The rule is: Update: dummy->0, Insert: preserve dummy value */
186 /* These tables do not require deletions since we cannot have such condition (object_id==0 AND thread_id==0) */
187 if((tr->class_type==C_PN) || (tr->class_type==C_RO) ||
188 (tr->class_type==C_AS) || (tr->class_type==C_RS) ||
189 (tr->class_type==C_MT)){
190
191 /* Process the rows updated/touched */
192 g_string_sprintf(query, "UPDATE %s SET thread_id=0, dummy=0 WHERE object_id=%ld AND thread_id=%d ", DF_get_class_sql_table(tr->class_type), tr->object_id, tr->thread_upd);
193 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
194 }
195
196 switch (tr->class_type) {
197 case C_IR:
198 case C_IN:
199 case C_I6:
200 case C_FS:
201 if((tr->save)){ /* Some special processing for tables with the second attribute */
202 /* Update the second field of the table with query like one below */
203 /* UPDATE %s SET thread_id=%d, local_as='%s' WHERE object_id=%ld */
204
205 switch(tr->class_type) {
206 /* Local-as for inet-rtr */
207 case C_IR: attr_type=A_LA;
208 break;
209 /* netname for inetnum and inet6num */
210 case C_IN:
211 case C_I6: attr_type=A_NA;
212 break;
213 /* filter for filter-set */
214 case C_FS: attr_type=A_FI;
215 break;
216 default:
217 die;
218 break;
219 }
220 g_string_sprintf(query, DF_get_update_query(attr_type), DF_get_class_sql_table(tr->class_type), 0, (char *)tr->save, tr->object_id);
221 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
222 }
223 else die;
224 break;
225
226 default:
227 /* Process all other MAIN tables for updates/inserts and person_role, mntner, as_set, route_set tables for rows inserts */
228 g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld AND thread_id>0", DF_get_class_sql_table(tr->class_type), tr->object_id);
229 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
230 break;
231 }
232
233
234 /* for tables that might be affected by dummies */
235 for(j=0; j < tr->ndummy; j++)/* if dummies have been created */
236 for (i=0; tables[tr->class_type][i] != NULL; i++) {
237 g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld ", tables[tr->class_type][i], tr->dummy_id[j]);
238 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
239 }
240
241
242 for(j=0; j < tr->ndummy; j++){/* if dummies have been created*/
243 g_string_sprintf(query, "UPDATE last SET thread_id=0 WHERE object_id=%ld ", tr->dummy_id[j]);
244 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
245 }
246
247 /* Unlock all tables */
248 g_string_sprintf(query, "UNLOCK TABLES ");
249 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
250
251 /* Update radix tree for route, inetnum and inaddr-arpa domain*/
252 if(tr->standalone==0) { /* only if server*/
253
254 /* Create a radix node for the object */
255 if( ( (tr->class_type==C_RT)
256 || (tr->class_type==C_IN)
257 || (tr->class_type==C_I6)
258 || (tr->class_type==C_DN))
259 && (tr->packptr)) {
260 rp_upd_pack_t *packptr = tr->packptr;
261
262 packptr->key = tr->object_id;
263
264 if( RP_pack_node(RX_OPER_CRE, packptr, RIPE_REG) == RX_OK ) {
265 err = 0;
266 } else {
267 err = (-1) ;
268 }
269 }
270 /* XXX Check for errors */
271 }
272
273 g_string_free(query, TRUE);
274 return(err);
275 } /* commit() */
276
277
278
279 /******************************************************
280 *int delete(Transaction_t *tr)
281 * Delete the object
282 *
283 *****************************************************/
284 int delete(Transaction_t *tr)
/* [<][>][^][v][top][bottom][index][help] */
285 {
286 GString *query;
287 int err=0;
288 int i;
289 int num;
290 long ref_id;
291 long num_rec;
292 long timestamp;
293
294 char sobject_id[STR_M];
295 char *sql_str;
296 int sql_err;
297
298
299 /* Try to allocate g_string. Return on error */
300 if ((query = g_string_sized_new(STR_XXL)) == NULL){
301 fprintf(stderr, "E: cannot allocate gstring\n");
302 tr->succeeded=0;
303 tr->error|=ERROR_U_MEM;
304 return(ERROR_U_MEM);
305 }
306
307
308 /* Check for referential integrity of deletion */
309
310 sprintf(sobject_id, "%ld", tr->object_id);
311
312 switch(tr->class_type){
313 case C_PN:
314 case C_RO:
315
316 if(tr->dummy==1)break; /* This is if the override exists */
317
318 /* Check that this person/role object is not referenced */
319
320 for (i=0; t_ipn[i] != NULL; i++) {
321 /* Calculate number of references */
322 sql_str= get_field_str(tr->sql_connection, "COUNT(*)", t_ipn[i], "pe_ro_id", sobject_id, NULL);
323 if(sql_str) {
324 num_rec = atol(sql_str); free(sql_str);
325 ref_id=tr->object_id;
326 /* Check if it is a self reference (for role objects) */
327 if(num_rec==1) {
328 sql_str= get_field_str(tr->sql_connection, "object_id", t_ipn[i], "pe_ro_id", sobject_id, NULL);
329 if(sql_str) {
330 ref_id = atol(sql_str); free(sql_str);
331 } else {
332 tr->succeeded=0; tr->error |= ERROR_U_DBS; break;
333 }
334 }
335 /* If there are references (and not the only self reference) we cannot delete */
336 if((num_rec>1) || (ref_id!=tr->object_id)) {
337 g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, t_ipn[i]);
338 tr->succeeded=0; tr->error |= ERROR_U_OBJ;
339 }
340 } else {
341 /* SQL error occured */
342 tr->succeeded=0; tr->error |= ERROR_U_DBS;
343 g_string_sprintfa(tr->error_script,"E[%d][%s]:%s\n", ERROR_U_DBS, t_ipn[i], SQ_error(tr->sql_connection));
344 }
345 }
346
347 /* Check that this person/role object is not referenced by name (legacy stuff) */
348
349 for (i=0; t_ipn[i] != NULL; i++) {
350 /* Calculate number of references */
351
352 g_string_sprintf(query, "SELECT COUNT(*) FROM %s, person_role "
353 "WHERE person_role.object_id=%s.pe_ro_id "
354 "AND person_role.nic_hdl='%s' ", t_ipn[i], t_ipn[i], tr->save);
355
356 sql_str= get_qresult_str(tr->sql_connection, query->str);
357 if(sql_str) {
358 num_rec = atol(sql_str); free(sql_str);
359 /* If there are references (no self reference is possible in this case) we cannot delete */
360 if(num_rec>0) {
361 g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, t_ipn[i]);
362 tr->succeeded=0; tr->error |= ERROR_U_OBJ;
363 }
364 } else {
365 /* SQL error occured */
366 tr->succeeded=0; tr->error |= ERROR_U_DBS;
367 g_string_sprintfa(tr->error_script,"E[%d][%s]:%s\n", ERROR_U_DBS, t_ipn[i], SQ_error(tr->sql_connection));
368 }
369 }
370
371 break;
372
373 case C_MT:
374
375 if(tr->dummy==1)break; /* This is if the override exists */
376
377 /* Check that this mntner object is not referenced */
378
379 for (i=0; t_imt[i] != NULL; i++) {
380 /* Calculate number of references */
381 sql_str= get_field_str(tr->sql_connection, "COUNT(*)", t_imt[i], "mnt_id", sobject_id, NULL);
382 if(sql_str) {
383 num_rec = atol(sql_str); free(sql_str);
384 ref_id=tr->object_id;
385 /* Check if it is a self reference */
386 if(num_rec==1) {
387 sql_str= get_field_str(tr->sql_connection, "object_id", t_imt[i], "mnt_id", sobject_id, NULL);
388 if(sql_str) {
389 ref_id = atol(sql_str); free(sql_str);
390 } else {
391 tr->succeeded=0; tr->error |= ERROR_U_DBS; break;
392 }
393 }
394 /* If there are references (and not the only self reference) we cannot delete */
395 if((num_rec>1) || (ref_id!=tr->object_id)) {
396 g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, t_imt[i]);
397 tr->succeeded=0; tr->error |= ERROR_U_OBJ;
398 }
399 } else {
400 tr->succeeded=0; tr->error |= ERROR_U_DBS;
401 }
402 }
403 break;
404
405 case C_RS:
406 case C_AS:
407 /* Check that this set object is not referenced */
408 /* Calculate number of references */
409 sql_str= get_field_str(tr->sql_connection, "COUNT(*)", "member_of", "set_id", sobject_id, NULL);
410 if(sql_str) {
411 num_rec = atol(sql_str); free(sql_str);
412 /* XXX though set may contain other sets as memebers, */
413 /* there is no member-of attribute in these objects. */
414 /* So no self-reference is possible */
415 if(num_rec!=0) {
416 g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, "member_of");
417 tr->succeeded=0; tr->error |= ERROR_U_OBJ;
418 /* XXX Do not refuse the transaction but change the object to dummy */
419 }
420 } else {
421 tr->succeeded=0; tr->error |= ERROR_U_DBS;
422 }
423 break;
424
425 default:
426 break;
427 }
428
429 /* Check if we have passed referential integrity check */
430 if(tr->succeeded==0){
431 return(-1);
432 }
433
434
435 /* Lock all relevant tables */
436 g_string_sprintf(query, "LOCK TABLES %s WRITE,", DF_get_class_sql_table(tr->class_type));
437
438 for (i=0; tables[tr->class_type][i] != NULL; i++)
439 g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
440
441 for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
442 g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
443
444 g_string_sprintfa(query, " last WRITE, history WRITE ");
445
446 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
447
448 for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
449 g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", tables[tr->class_type][i], tr->object_id);
450 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
451 /* fprintf(stderr, "D: query (delete): %s\n", query->str);*/
452 }
453
454 /* Process the MAIN table */
455 g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", DF_get_class_sql_table(tr->class_type), tr->object_id);
456 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
457
458 /* Update the history table */
459 g_string_sprintf(query, "INSERT history "
460 "SELECT 0, object_id, sequence_id, timestamp, object_type, object "
461 "FROM last "
462 "WHERE object_id=%ld ", tr->object_id);
463
464
465 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
466 if (sql_err) {
467 fprintf(stderr, "E ERROR!<perform_update>: INSERT history failed:[%d][%s]\n", num, query->str);
468 tr->succeeded=0;
469 tr->error |=ERROR_U_DBS;
470 }
471
472 /* get sequence number */
473 tr->sequence_id = get_sequence_id(tr);
474 tr->sequence_id++;
475
476 /* insert new version into the last */
477 timestamp=time(NULL);
478
479 /* empty the contents, but leave in the table to restrict re-use of object_id */
480 g_string_sprintf(query, "UPDATE last SET object='', timestamp=%ld WHERE object_id=%ld ", timestamp, tr->object_id);
481
482 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
483 if (sql_err) {
484 fprintf(stderr, "E ERROR!<perform_update>: UPDATE last failed: [%d][%s]\n", num, query->str);
485 tr->succeeded=0;
486 tr->error |= ERROR_U_DBS;
487 }
488
489
490 /* Do more in the forest
491 * Update radix tree for route and inetnum
492 */
493 if(tr->standalone==0) { /* only if server */
494 /* Collect some data for radix tree and NH repository update */
495 g_slist_foreach((tr->object)->attributes, get_rx_data, tr);
496
497 /* Only for these types of objects and only if we have collected data (tr->save != NULL) */
498 if( ( (tr->class_type==C_RT)
499 || (tr->class_type==C_IN)
500 || (tr->class_type==C_I6)
501 || (tr->class_type==C_DN))
502 && (tr->packptr)) {
503 rp_upd_pack_t *packptr = tr->packptr;
504
505 packptr->key = tr->object_id;
506 if( RP_pack_node(RX_OPER_DEL, packptr, RIPE_REG) == RX_OK ) {
507 err = 0;
508 } else {
509 err = (-1) ;
510 }
511 }
512 }
513
514 /* Unlock all tables */
515 g_string_sprintf(query, "UNLOCK TABLES ");
516 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
517
518 g_string_free(query, TRUE);
519
520 return(err);
521
522 } /* delete() */