modules/ud/ud_comrol.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- UD_rollback
- UD_commit_I
- UD_commit_II
- UD_commit
- UD_check_ref
- UD_delete
- UD_update_rx
1 /***************************************
2 $Revision: 1.29 $
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,2001 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
34 #include "rip.h"
35 #include "ud_comrol.h"
36
37
38 /************************************************************
39 * int UD_rollback() *
40 * *
41 * Rolls back the transaction *
42 * *
43 * It locks all relevant tables and processes the rollback *
44 * General approach is to delete all new records related *
45 * to the transaction (thread_id==thread_ins) and clean up *
46 * old ones (thread_id==thread_upd) *
47 * *
48 ************************************************************/
49
50 int UD_rollback(Transaction_t *tr) {
/* [<][>][^][v][top][bottom][index][help] */
51 GString *query;
52 int i, j;
53 int sql_err;
54
55 if(ACT_DELETE(tr->action)) return(0);
56
57 if ((query = g_string_sized_new(STR_XXL)) == NULL){
58 ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
59 tr->succeeded=0;
60 tr->error |= ERROR_U_MEM;
61 die;
62 }
63
64 /* Lock all relevant tables */
65 g_string_sprintf(query, "LOCK TABLES ");
66
67 /* we need to lock tables for mntner and role differently, otherwise there will be duplicates (names names, etc.)*/
68 if((tr->class_type!=C_MT) && (tr->class_type!=C_RO)){
69 g_string_sprintfa(query, " %s WRITE,", DF_get_class_sql_table(tr->class_type));
70
71 for (i=0; tables[tr->class_type][i] != NULL; i++)
72 g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
73 } else { /* mntner and role are special cases */
74 g_string_sprintfa(query, " mntner WRITE, person_role WRITE, ");
75 }
76
77 for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
78 g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
79
80 g_string_sprintfa(query, " last WRITE, history WRITE ");
81
82 sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
83
84 /* Process AUX and LEAF tables */
85 for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
86 /* Delete what has been inserted */
87 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);
88 sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
89
90 /* Normalize what has been updated/touched */
91 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);
92 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
93 }
94
95 /* Process MAIN tables */
96 /* Delete if a record was created */
97 g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld AND thread_id=%d",
98 DF_get_class_sql_table(tr->class_type), tr->object_id, tr->thread_ins);
99 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
100
101 /* This is needed only for objects with possible dummy type, as they are updated with TR_UPDATE */
102 /* We use this tag when committing the update to set dummy==0 */
103 /* XXX may be later this should be reconsidered */
104 g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld AND thread_id=%d",
105 DF_get_class_sql_table(tr->class_type), tr->object_id, tr->thread_upd);
106 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
107
108 /* Now tables that might be affected by dummies */
109 for(j=0; j < tr->ndummy; j++)
110 for (i=0; tables[tr->class_type][i] != NULL; i++) {
111 g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", tables[tr->class_type][i], tr->dummy_id[j]);
112 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
113 }
114
115 /* if dummies have been created - get rid of them */
116 for(j=0; j < tr->ndummy; j++){
117 g_string_sprintf(query, "DELETE FROM last WHERE object_id=%ld ", tr->dummy_id[j]);
118 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
119 }
120
121 /* Rollback last and history tables */
122
123 /* Delete what has been inserted */
124 g_string_sprintf(query, "DELETE FROM history WHERE object_id=%ld AND thread_id=%d", tr->object_id, tr->thread_ins);
125 sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
126
127 /* Normalize what has been updated/touched */
128 g_string_sprintf(query, "UPDATE history SET thread_id=0 WHERE object_id=%ld AND thread_id=%d", tr->object_id, tr->thread_upd);
129 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
130
131 /* Delete what has been inserted */
132 g_string_sprintf(query, "DELETE FROM last WHERE object_id=%ld AND thread_id=%d", tr->object_id, tr->thread_ins);
133 sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
134
135 /* Normalize what has been updated/touched */
136 g_string_sprintf(query, "UPDATE last SET thread_id=0 WHERE object_id=%ld AND thread_id=%d", tr->object_id, tr->thread_upd);
137 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
138
139
140 /* Unlock all tables */
141 g_string_sprintf(query, "UNLOCK TABLES ");
142 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
143
144
145 g_string_free(query, TRUE);
146 return(0);
147 } /* rollback() */
148
149 /************************************************************
150 * int UD_commit_I() *
151 * *
152 * Performs I phase of the commit - deletions *
153 * *
154 * General approach is to delete untouched rec (thread_id==0)*
155 * *
156 ************************************************************/
157
158 int UD_commit_I(Transaction_t *tr) {
/* [<][>][^][v][top][bottom][index][help] */
159 GString *query;
160 int err=0;
161 int i;
162 int sql_err;
163
164
165 if ((query = g_string_sized_new(STR_XXL)) == NULL){
166 ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
167 tr->succeeded=0;
168 tr->error|=ERROR_U_MEM;
169 die;
170 }
171
172 /* Commit the transaction for AUX and LEAF tables that may be affected (taken from object template) */
173 for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
174 /* Delete old records from the tables */
175 g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld AND thread_id=0 ", tables[tr->class_type][i], tr->object_id);
176 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
177 /* ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s query (del old): %s\n", UD_TAG, query->str); */
178 }
179
180 /* Delete old record from the last table */
181 g_string_sprintf(query, "DELETE FROM last WHERE object_id=%ld AND thread_id=0 ", tr->object_id);
182 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
183 /* ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s query (del old): %s\n", UD_TAG, query->str); */
184
185
186 g_string_free(query, TRUE);
187 return(err);
188 }
189
190 /************************************************************
191 * int UD_commit_II() *
192 * *
193 * Performs I phase of the commit - deletions *
194 * General approach is to clean up all new and updated *
195 * records related to the transaction *
196 * (thread_id==thread_ins) and (thread_id==thread_upd) *
197 * *
198 ************************************************************/
199 int UD_commit_II(Transaction_t *tr) {
/* [<][>][^][v][top][bottom][index][help] */
200 GString *query;
201 int err=0;
202 int i,j;
203 A_Type_t attr_type;
204 int sql_err;
205
206
207 if ((query = g_string_sized_new(STR_XXL)) == NULL){
208 ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
209 tr->succeeded=0;
210 tr->error|=ERROR_U_MEM;
211 die;
212 }
213
214
215 /* Commit the transaction for AUX and LEAF tables that may be affected (taken from object template) */
216 for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
217 /* Set thread_id to 0 to commit the transaction */
218 g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld", tables[tr->class_type][i], tr->object_id);
219 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
220 /* ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s query (com new): %s\n", UD_TAG, query->str); */
221 }
222
223 /* Commit changes to the last table */
224 g_string_sprintf(query, "UPDATE last SET thread_id=0 WHERE object_id=%ld ", tr->object_id);
225 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
226
227 /* Commit changes to the history table */
228 g_string_sprintf(query, "UPDATE history SET thread_id=0 WHERE object_id=%ld ", tr->object_id);
229 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
230
231 /* Commit the transaction for the MAIN tables */
232
233 /* Commit the transaction for person_role, mntner, as_set, route_set tables */
234 /* They require different handling because of dummies */
235 /* The rule is: Update: dummy->0, Insert: preserve dummy value */
236 /* These tables do not require deletions since we cannot have such condition (object_id==0 AND thread_id==0) */
237 if((tr->class_type==C_PN) || (tr->class_type==C_RO) ||
238 (tr->class_type==C_AS) || (tr->class_type==C_RS) ||
239 (tr->class_type==C_MT)){
240
241 /* Process the rows updated/touched */
242 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);
243 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
244 }
245
246 switch (tr->class_type) {
247 case C_IR:
248 case C_IN:
249 case C_I6:
250 case C_FS:
251 if((tr->save)){ /* Some special processing for tables with the second attribute */
252 /* Update the second field of the table with query like one below */
253 /* UPDATE %s SET thread_id=%d, local_as='%s' WHERE object_id=%ld */
254
255 switch(tr->class_type) {
256 /* Local-as for inet-rtr */
257 case C_IR: attr_type=A_LA;
258 break;
259 /* netname for inetnum and inet6num */
260 case C_IN:
261 case C_I6: attr_type=A_NA;
262 break;
263 /* filter for filter-set */
264 case C_FS: attr_type=A_FI;
265 break;
266 default:
267 ER_perror(FAC_UD, UD_BUG, "not valid class type\n");
268 attr_type=A_END;
269 die;
270 }
271 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);
272 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
273 }
274 else {
275 ER_perror(FAC_UD, UD_BUG, "second attribute is not saved\n");
276 die;
277 }
278 break;
279
280 default:
281 /* Process all other MAIN tables for updates/inserts and person_role, mntner, as_set, route_set tables for rows inserts */
282 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);
283 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
284 break;
285 }
286
287
288 /* for tables that might be affected by dummies */
289 for(j=0; j < tr->ndummy; j++)/* if dummies have been created */
290 for (i=0; tables[tr->class_type][i] != NULL; i++) {
291 g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld ", tables[tr->class_type][i], tr->dummy_id[j]);
292 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
293 }
294
295
296 for(j=0; j < tr->ndummy; j++){/* if dummies have been created*/
297 g_string_sprintf(query, "UPDATE last SET thread_id=0 WHERE object_id=%ld ", tr->dummy_id[j]);
298 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
299 }
300
301 g_string_free(query, TRUE);
302
303 return(err);
304 }
305
306
307 /************************************************************
308 * int UD_commit() *
309 * *
310 * Commits the transaction *
311 * *
312 * It locks all relevant tables and processes the 2 phases of*
313 * commit. It also performs checkpointing of phases and *
314 * radix tree update *
315 * *
316 * We need to split commit into 2 because otherwise it is *
317 * hard to distinguish between commited records and untouched*
318 * ones (both have thread_id==0). Splitting and checkpointing*
319 * solves this problem *
320 * *
321 ************************************************************/
322
323 int UD_commit(Transaction_t *tr) {
/* [<][>][^][v][top][bottom][index][help] */
324 GString *query;
325 int err=0;
326 int i;
327 int sql_err;
328
329 if(ACT_DELETE(tr->action)) return(0);
330
331 if ((query = g_string_sized_new(STR_XXL)) == NULL){
332 ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
333 tr->succeeded=0;
334 tr->error|=ERROR_U_MEM;
335 die;
336 }
337
338 /* Lock all relevant tables */
339 g_string_sprintf(query, "LOCK TABLES ");
340
341 /* we need to lock tables for mntner and role differently, otherwise there will be duplicates (names names, etc.)*/
342 /* if((tr->class_type!=C_MT) && (tr->class_type!=C_RO)){ */
343 g_string_sprintfa(query, " %s WRITE,", DF_get_class_sql_table(tr->class_type));
344
345 if((tr->class_type==C_RO)) g_string_sprintfa(query, " mntner WRITE, ");
346 else if((tr->class_type==C_MT)) g_string_sprintfa(query, " person_role WRITE, names WRITE, ");
347 else
348 for (i=0; tables[tr->class_type][i] != NULL; i++)
349 g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
350
351 for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
352 g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
353
354 g_string_sprintfa(query, " last WRITE, history WRITE, transaction_rec WRITE ");
355
356 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
357
358
359 /* Perform first phase - deletions */
360 UD_commit_I(tr);
361 /* checkpoint this step */
362 CP_COMMIT_I_PASSED(tr->action); TR_update_status(tr);
363 /* Perform first phase - updates */
364 UD_commit_II(tr);
365 /* checkpoint this step */
366 CP_COMMIT_II_PASSED(tr->action); TR_update_status(tr);
367
368 /* Unlock all tables */
369 g_string_sprintf(query, "UNLOCK TABLES ");
370 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
371
372 /* Update radix tree for route, inetnum and inaddr-arpa domain*/
373 err = UD_update_rx(tr, RX_OPER_CRE);
374
375 g_string_free(query, TRUE);
376 return(err);
377 } /* commit() */
378
379 /************************************************************
380 * int UD_check_ref() *
381 * *
382 * Checks if the object to be deleted is referenced from *
383 * anywhere *
384 * *
385 * 0 - go ahead *
386 * -1 - deletion will compromise ref.integrity *
387 * Result is also reflected in tr->succeeded *
388 ************************************************************/
389 int UD_check_ref(Transaction_t *tr)
/* [<][>][^][v][top][bottom][index][help] */
390 {
391 GString *query;
392 int i;
393 long ref_id;
394 long num_rec;
395
396 char sobject_id[STR_M];
397 char *sql_str;
398
399 /* Try to allocate g_string. Return on error */
400 if ((query = g_string_sized_new(STR_XXL)) == NULL){
401 ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
402 tr->succeeded=0;
403 tr->error|=ERROR_U_MEM;
404 die;
405 }
406
407
408 /* Check for referential integrity of deletion */
409
410 sprintf(sobject_id, "%ld", tr->object_id);
411
412 switch(tr->class_type){
413 case C_PN:
414 case C_RO:
415
416 /* Check that this person/role object is not referenced */
417
418 for (i=0; t_ipn[i] != NULL; i++) {
419 /* Calculate number of references */
420 sql_str= get_field_str(tr->sql_connection, "COUNT(*)", t_ipn[i], "pe_ro_id", sobject_id, NULL);
421 if(sql_str) {
422 num_rec = atol(sql_str); UT_free(sql_str);
423 ref_id=tr->object_id;
424 /* Check if it is a self reference (for role objects) */
425 if(num_rec==1) {
426 sql_str= get_field_str(tr->sql_connection, "object_id", t_ipn[i], "pe_ro_id", sobject_id, NULL);
427 if(sql_str) {
428 ref_id = atol(sql_str); UT_free(sql_str);
429 } else {
430 /* this is not possible unless it is an sql error */
431 /*XXX probably we need to die */
432 tr->succeeded=0; tr->error |= ERROR_U_DBS; break;
433 }
434 }
435 /* If there are references (and not the only self reference) we cannot delete */
436 if((num_rec>1) || (ref_id!=tr->object_id)) {
437 g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, t_ipn[i]);
438 tr->succeeded=0; tr->error |= ERROR_U_OBJ;
439 }
440 } else {
441 /* SQL error occured */
442 tr->succeeded=0; tr->error |= ERROR_U_DBS;
443 g_string_sprintfa(tr->error_script,"E[%d][%s]:%s\n", ERROR_U_DBS, t_ipn[i], SQ_error(tr->sql_connection));
444 }
445 }
446
447 /* Check that this person/role object is not referenced by name (legacy stuff) */
448 /* But allow overriding this check in NRTM mode and with override_integrity */
449 if(IS_DUMMY_ALLOWED(tr->mode))break;
450
451 for (i=0; t_ipn[i] != NULL; i++) {
452 /* Calculate number of references */
453
454 g_string_sprintf(query, "SELECT COUNT(*) FROM %s, person_role "
455 "WHERE person_role.object_id=%s.pe_ro_id "
456 "AND person_role.nic_hdl='%s' ", t_ipn[i], t_ipn[i], tr->save);
457
458 sql_str= get_qresult_str(tr->sql_connection, query->str);
459 if(sql_str) {
460 num_rec = atol(sql_str); UT_free(sql_str);
461 /* If there are references (no self reference is possible in this case) we cannot delete */
462 if(num_rec>0) {
463 g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, t_ipn[i]);
464 tr->succeeded=0; tr->error |= ERROR_U_OBJ;
465 }
466 } else {
467 /* SQL error occured */
468 tr->succeeded=0; tr->error |= ERROR_U_DBS;
469 g_string_sprintfa(tr->error_script,"E[%d][%s]:%s\n", ERROR_U_DBS, t_ipn[i], SQ_error(tr->sql_connection));
470 }
471 }
472
473 break;
474
475 case C_MT:
476
477 /* Check that this mntner object is not referenced */
478
479 for (i=0; t_imt[i] != NULL; i++) {
480 /* Calculate number of references */
481 sql_str= get_field_str(tr->sql_connection, "COUNT(*)", t_imt[i], "mnt_id", sobject_id, NULL);
482 if(sql_str) {
483 num_rec = atol(sql_str); UT_free(sql_str);
484 ref_id=tr->object_id;
485 /* Check if it is a self reference */
486 if(num_rec==1) {
487 sql_str= get_field_str(tr->sql_connection, "object_id", t_imt[i], "mnt_id", sobject_id, NULL);
488 if(sql_str) {
489 ref_id = atol(sql_str); UT_free(sql_str);
490 } else {
491 tr->succeeded=0; tr->error |= ERROR_U_DBS; break;
492 }
493 }
494 /* If there are references (and not the only self reference) we cannot delete */
495 if((num_rec>1) || (ref_id!=tr->object_id)) {
496 g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, t_imt[i]);
497 tr->succeeded=0; tr->error |= ERROR_U_OBJ;
498 }
499 } else {
500 tr->succeeded=0; tr->error |= ERROR_U_DBS;
501 }
502 }
503 break;
504
505 case C_RS:
506 case C_AS:
507 /* Check that this set object is not referenced */
508 /* Calculate number of references */
509 sql_str= get_field_str(tr->sql_connection, "COUNT(*)", "member_of", "set_id", sobject_id, NULL);
510 if(sql_str) {
511 num_rec = atol(sql_str); UT_free(sql_str);
512 /* XXX though set may contain other sets as memebers, */
513 /* there is no member-of attribute in these objects. */
514 /* So no self-reference is possible */
515 if(num_rec!=0) {
516 g_string_sprintfa(tr->error_script,"I[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, "member_of");
517 /* XXX Do not refuse the transaction but change the object to dummy */
518 tr->action |=TA_DUMMY;
519 }
520 } else {
521 tr->succeeded=0; tr->error |= ERROR_U_DBS;
522 }
523 break;
524
525 default:
526 break;
527 }
528
529 g_string_free(query, TRUE);
530
531 /* Check if we have passed referential integrity check */
532 if(tr->succeeded) return(0); else return(-1);
533
534 }
535
536 /************************************************************
537 * int UD_delete() *
538 * *
539 * Deletes the object *
540 * *
541 * It deletes the object from all relevant tables.
542 * Then it updates the radix tree for routes, inetnums
543 * and rev.domains *
544 * *
545 ************************************************************/
546 int UD_delete(Transaction_t *tr)
/* [<][>][^][v][top][bottom][index][help] */
547 {
548 GString *query;
549 int err=0;
550 int i;
551 long timestamp;
552 int sql_err;
553 int ref_set;
554
555 /* if we are deliting referenced set, we need to perform delete a bit differently */
556 /* no deletions of aux tables */
557 /* dummy main, instead of del */
558 /* dummy last instead of empty */
559 /* So let's determine if we are deliting referenced set */
560 if ((tr->class_type==C_AS || tr->class_type==C_RS) && ACT_UPD_DUMMY(tr->action)) ref_set = 1; else ref_set = 0;
561
562 /* Try to allocate g_string. Return on error */
563 if ((query = g_string_sized_new(STR_XXL)) == NULL){
564 ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
565 tr->succeeded=0;
566 tr->error|=ERROR_U_MEM;
567 die;
568 }
569
570
571 /* Lock all relevant tables */
572 g_string_sprintf(query, "LOCK TABLES ");
573
574 /* we need to lock tables for mntner and role differently, otherwise there will be duplicates (names names, etc.)*/
575 if((tr->class_type!=C_MT) && (tr->class_type!=C_RO)){
576 g_string_sprintfa(query, " %s WRITE,", DF_get_class_sql_table(tr->class_type));
577
578 for (i=0; tables[tr->class_type][i] != NULL; i++)
579 g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
580 } else { /* mntner and role are special cases */
581 g_string_sprintfa(query, " mntner WRITE, person_role WRITE, ");
582 }
583
584 for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
585 g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
586
587 g_string_sprintfa(query, " last WRITE, history WRITE ");
588
589 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
590 if (sql_err) {
591 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
592 tr->succeeded=0;
593 tr->error |=ERROR_U_DBS;
594 die;
595 }
596 /* Update the history table */
597 /* XXX Crash recovery: */
598 /* If history was not updated - we will create a record */
599 /* If history was already updated but last wasn't - we will just replace the record */
600 /* If history and last were already updated - we will have an empty query - 0 rows should be affected */
601 g_string_sprintf(query, "REPLACE history "
602 "SELECT 0, object_id, sequence_id, timestamp, object_type, object, pkey, serial, prev_serial "
603 "FROM last "
604 "WHERE object_id=%ld AND sequence_id=%ld ", tr->object_id, tr->sequence_id);
605 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
606 if (sql_err) {
607 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
608 tr->succeeded=0;
609 tr->error |=ERROR_U_DBS;
610 die;
611 }
612
613 /* Delete records from the leaf and aux tables */
614 for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
615 g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", tables[tr->class_type][i], tr->object_id);
616 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
617 /* ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s query (delete): %s\n", UD_TAG, query->str);*/
618 if (sql_err) {
619 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
620 tr->succeeded=0;
621 tr->error |=ERROR_U_DBS;
622 die;
623 }
624 }
625
626
627 /* For all object except as-sets and route-sets we need to empty MAIN table */
628 /* For referenced sets, however, we transform them to dummy, not delete */
629 if (ref_set == 0) {
630
631 /* Process the MAIN table */
632 g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", DF_get_class_sql_table(tr->class_type), tr->object_id);
633
634
635 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
636 if (sql_err) {
637 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
638 tr->succeeded=0;
639 tr->error |=ERROR_U_DBS;
640 die;
641 }
642
643 } else { /* this is the referenced set */
644 /* we need to 'dummy' MAIN */
645 g_string_sprintf(query, "UPDATE %s SET dummy=1 WHERE object_id=%ld ", DF_get_class_sql_table(tr->class_type), tr->object_id);
646
647 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
648 if (sql_err) {
649 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
650 tr->succeeded=0;
651 tr->error |= ERROR_U_DBS;
652 die;
653 }
654 }
655
656 /* insert new version into the last */
657 timestamp=time(NULL);
658
659 if(ref_set == 0)
660 {
661 /* empty the contents, but leave in the table to restrict re-use of object_id */
662 /* XXX change sequence_id=0 so it is easy to say that the object was deleted */
663 g_string_sprintf(query, "UPDATE last SET object='', timestamp=%ld, sequence_id=0 WHERE object_id=%ld ", timestamp, tr->object_id);
664
665 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
666 if (sql_err) {
667 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
668 tr->succeeded=0;
669 tr->error |= ERROR_U_DBS;
670 die;
671 }
672 } else {/* this is the referenced set */
673 /* 'dummy' the contents, but leave in the table to prevent re-use of object_id */
674 g_string_sprintf(query, "UPDATE last SET object='DUMMY SET', object_type=%d, sequence_id=%ld, timestamp=%ld WHERE object_id=%ld ", DUMMY_TYPE, tr->sequence_id+1, timestamp, tr->object_id);
675
676 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
677 if (sql_err) {
678 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
679 tr->succeeded=0;
680 tr->error |= ERROR_U_DBS;
681 die;
682 }
683 }
684
685
686 /* Unlock all tables */
687 g_string_sprintf(query, "UNLOCK TABLES ");
688 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
689 if (sql_err) {
690 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
691 tr->succeeded=0;
692 tr->error |= ERROR_U_DBS;
693 die;
694 }
695
696
697 g_string_free(query, TRUE);
698
699 return(err);
700
701 } /* delete() */
702
703
704
705 /* Do more in the forest
706 * Update radix tree for route and inetnum
707 */
708
709 int UD_update_rx(Transaction_t *tr, rx_oper_mt mode)
/* [<][>][^][v][top][bottom][index][help] */
710 {
711 rp_upd_pack_t *packptr = tr->packptr;
712 int err=0;
713
714
715 if(!IS_STANDALONE(tr->mode)) { /* only if server */
716
717
718 /* Only for these types of objects and only if we have collected data (tr->save != NULL) */
719 if( ( (tr->class_type==C_RT)
720 || (tr->class_type==C_IN)
721 || (tr->class_type==C_I6)
722 || (tr->class_type==C_DN))) {
723 /* Collect some data for radix tree and NH repository update for deletes*/
724 if(mode == RX_OPER_DEL)g_slist_foreach((tr->object)->attributes, get_rx_data, tr);
725
726 /* Except for regular domains we need to update radix tree */
727 if(ACT_UPD_RX(tr->action)){
728 packptr->key = tr->object_id;
729 if( RP_pack_node(mode, packptr, tr->source_hdl) == RX_OK ) {
730 err = 0;
731 } else {
732 err = (-1);
733 ER_perror(FAC_UD, UD_BUG, "cannot update radix tree\n");
734 die;
735 }
736 } /* update radix tree */
737 }
738 }
739 return(err);
740 }
741
742
743