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.26 $
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 "ud_tr.h"
37 #include "rp.h"
38
39
40 /************************************************************
41 * int UD_rollback() *
42 * *
43 * Rolls back the transaction *
44 * *
45 * It locks all relevant tables and processes the rollback *
46 * General approach is to delete all new records related *
47 * to the transaction (thread_id==thread_ins) and clean up *
48 * old ones (thread_id==thread_upd) *
49 * *
50 ************************************************************/
51
52 int UD_rollback(Transaction_t *tr) {
/* [<][>][^][v][top][bottom][index][help] */
53 GString *query;
54 int i, j;
55 int sql_err;
56
57 if(ACT_DELETE(tr->action)) return(0);
58
59 if ((query = g_string_sized_new(STR_XXL)) == NULL){
60 ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
61 tr->succeeded=0;
62 tr->error |= ERROR_U_MEM;
63 die;
64 }
65
66 /* Lock all relevant tables */
67 g_string_sprintf(query, "LOCK TABLES ");
68
69 /* we need to lock tables for mntner and role differently, otherwise there will be duplicates (names names, etc.)*/
70 if((tr->class_type!=C_MT) && (tr->class_type!=C_RO)){
71 g_string_sprintfa(query, " %s WRITE,", DF_get_class_sql_table(tr->class_type));
72
73 for (i=0; tables[tr->class_type][i] != NULL; i++)
74 g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
75 } else { /* mntner and role are special cases */
76 g_string_sprintfa(query, " mntner WRITE, person_role WRITE, ");
77 }
78
79 for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
80 g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
81
82 g_string_sprintfa(query, " last WRITE, history WRITE ");
83
84 sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
85
86 /* Process AUX and LEAF tables */
87 for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
88 /* Delete what has been inserted */
89 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);
90 sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
91
92 /* Normalize what has been updated/touched */
93 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);
94 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
95 }
96
97 /* Process MAIN tables */
98 /* Delete if a record was created */
99 g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld AND thread_id=%d",
100 DF_get_class_sql_table(tr->class_type), tr->object_id, tr->thread_ins);
101 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
102
103 /* This is needed only for objects with possible dummy type, as they are updated with TR_UPDATE */
104 /* We use this tag when committing the update to set dummy==0 */
105 /* XXX may be later this should be reconsidered */
106 g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld AND thread_id=%d",
107 DF_get_class_sql_table(tr->class_type), tr->object_id, tr->thread_upd);
108 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
109
110 /* Now tables that might be affected by dummies */
111 for(j=0; j < tr->ndummy; j++)
112 for (i=0; tables[tr->class_type][i] != NULL; i++) {
113 g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", tables[tr->class_type][i], tr->dummy_id[j]);
114 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
115 }
116
117 /* if dummies have been created - get rid of them */
118 for(j=0; j < tr->ndummy; j++){
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 /* Rollback last and history tables */
124
125 /* Delete what has been inserted */
126 g_string_sprintf(query, "DELETE FROM history WHERE object_id=%ld AND thread_id=%d", tr->object_id, tr->thread_ins);
127 sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
128
129 /* Normalize what has been updated/touched */
130 g_string_sprintf(query, "UPDATE history SET thread_id=0 WHERE object_id=%ld AND thread_id=%d", tr->object_id, tr->thread_upd);
131 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
132
133 /* Delete what has been inserted */
134 g_string_sprintf(query, "DELETE FROM last WHERE object_id=%ld AND thread_id=%d", tr->object_id, tr->thread_ins);
135 sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
136
137 /* Normalize what has been updated/touched */
138 g_string_sprintf(query, "UPDATE last SET thread_id=0 WHERE object_id=%ld AND thread_id=%d", tr->object_id, tr->thread_upd);
139 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
140
141
142 /* Unlock all tables */
143 g_string_sprintf(query, "UNLOCK TABLES ");
144 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
145
146
147 g_string_free(query, TRUE);
148 return(0);
149 } /* rollback() */
150
151 /************************************************************
152 * int UD_commit_I() *
153 * *
154 * Performs I phase of the commit - deletions *
155 * *
156 * General approach is to delete untouched rec (thread_id==0)*
157 * *
158 ************************************************************/
159
160 int UD_commit_I(Transaction_t *tr) {
/* [<][>][^][v][top][bottom][index][help] */
161 GString *query;
162 int err=0;
163 int i;
164 int sql_err;
165
166
167 if ((query = g_string_sized_new(STR_XXL)) == NULL){
168 ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
169 tr->succeeded=0;
170 tr->error|=ERROR_U_MEM;
171 die;
172 }
173
174 /* Commit the transaction for AUX and LEAF tables that may be affected (taken from object template) */
175 for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
176 /* Delete old records from the tables */
177 g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld AND thread_id=0 ", tables[tr->class_type][i], tr->object_id);
178 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
179 /* ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s query (del old): %s\n", UD_TAG, query->str); */
180 }
181
182 /* Delete old record from the last table */
183 g_string_sprintf(query, "DELETE FROM last WHERE object_id=%ld AND thread_id=0 ", tr->object_id);
184 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
185 /* ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s query (del old): %s\n", UD_TAG, query->str); */
186
187
188 g_string_free(query, TRUE);
189 return(err);
190 }
191
192 /************************************************************
193 * int UD_commit_II() *
194 * *
195 * Performs I phase of the commit - deletions *
196 * General approach is to clean up all new and updated *
197 * records related to the transaction *
198 * (thread_id==thread_ins) and (thread_id==thread_upd) *
199 * *
200 ************************************************************/
201 int UD_commit_II(Transaction_t *tr) {
/* [<][>][^][v][top][bottom][index][help] */
202 GString *query;
203 int err=0;
204 int i,j;
205 A_Type_t attr_type;
206 int sql_err;
207
208
209 if ((query = g_string_sized_new(STR_XXL)) == NULL){
210 ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
211 tr->succeeded=0;
212 tr->error|=ERROR_U_MEM;
213 die;
214 }
215
216
217 /* Commit the transaction for AUX and LEAF tables that may be affected (taken from object template) */
218 for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
219 /* Set thread_id to 0 to commit the transaction */
220 g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld", tables[tr->class_type][i], tr->object_id);
221 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
222 /* ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s query (com new): %s\n", UD_TAG, query->str); */
223 }
224
225 /* Commit changes to the last table */
226 g_string_sprintf(query, "UPDATE last SET thread_id=0 WHERE object_id=%ld ", tr->object_id);
227 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
228
229 /* Commit changes to the history table */
230 g_string_sprintf(query, "UPDATE history SET thread_id=0 WHERE object_id=%ld ", tr->object_id);
231 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
232
233 /* Commit the transaction for the MAIN tables */
234
235 /* Commit the transaction for person_role, mntner, as_set, route_set tables */
236 /* They require different handling because of dummies */
237 /* The rule is: Update: dummy->0, Insert: preserve dummy value */
238 /* These tables do not require deletions since we cannot have such condition (object_id==0 AND thread_id==0) */
239 if((tr->class_type==C_PN) || (tr->class_type==C_RO) ||
240 (tr->class_type==C_AS) || (tr->class_type==C_RS) ||
241 (tr->class_type==C_MT)){
242
243 /* Process the rows updated/touched */
244 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);
245 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
246 }
247
248 switch (tr->class_type) {
249 case C_IR:
250 case C_IN:
251 case C_I6:
252 case C_FS:
253 if((tr->save)){ /* Some special processing for tables with the second attribute */
254 /* Update the second field of the table with query like one below */
255 /* UPDATE %s SET thread_id=%d, local_as='%s' WHERE object_id=%ld */
256
257 switch(tr->class_type) {
258 /* Local-as for inet-rtr */
259 case C_IR: attr_type=A_LA;
260 break;
261 /* netname for inetnum and inet6num */
262 case C_IN:
263 case C_I6: attr_type=A_NA;
264 break;
265 /* filter for filter-set */
266 case C_FS: attr_type=A_FI;
267 break;
268 default:
269 ER_perror(FAC_UD, UD_BUG, "not valid class type\n");
270 die;
271 break;
272 }
273 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);
274 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
275 }
276 else {
277 ER_perror(FAC_UD, UD_BUG, "second attribute is not saved\n");
278 die;
279 }
280 break;
281
282 default:
283 /* Process all other MAIN tables for updates/inserts and person_role, mntner, as_set, route_set tables for rows inserts */
284 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);
285 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
286 break;
287 }
288
289
290 /* for tables that might be affected by dummies */
291 for(j=0; j < tr->ndummy; j++)/* if dummies have been created */
292 for (i=0; tables[tr->class_type][i] != NULL; i++) {
293 g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld ", tables[tr->class_type][i], tr->dummy_id[j]);
294 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
295 }
296
297
298 for(j=0; j < tr->ndummy; j++){/* if dummies have been created*/
299 g_string_sprintf(query, "UPDATE last SET thread_id=0 WHERE object_id=%ld ", tr->dummy_id[j]);
300 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
301 }
302
303 g_string_free(query, TRUE);
304
305 return(err);
306 }
307
308
309 /************************************************************
310 * int UD_commit() *
311 * *
312 * Commits the transaction *
313 * *
314 * It locks all relevant tables and processes the 2 phases of*
315 * commit. It also performs checkpointing of phases and *
316 * radix tree update *
317 * *
318 * We need to split commit into 2 because otherwise it is *
319 * hard to distinguish between commited records and untouched*
320 * ones (both have thread_id==0). Splitting and checkpointing*
321 * solves this problem *
322 * *
323 ************************************************************/
324
325 int UD_commit(Transaction_t *tr) {
/* [<][>][^][v][top][bottom][index][help] */
326 GString *query;
327 int err=0;
328 int i;
329 int sql_err;
330
331 if(ACT_DELETE(tr->action)) return(0);
332
333 if ((query = g_string_sized_new(STR_XXL)) == NULL){
334 ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
335 tr->succeeded=0;
336 tr->error|=ERROR_U_MEM;
337 die;
338 }
339
340 /* Lock all relevant tables */
341 g_string_sprintf(query, "LOCK TABLES ");
342
343 /* we need to lock tables for mntner and role differently, otherwise there will be duplicates (names names, etc.)*/
344 /* if((tr->class_type!=C_MT) && (tr->class_type!=C_RO)){ */
345 g_string_sprintfa(query, " %s WRITE,", DF_get_class_sql_table(tr->class_type));
346
347 if((tr->class_type==C_RO)) g_string_sprintfa(query, " mntner WRITE, ");
348 else if((tr->class_type==C_MT)) g_string_sprintfa(query, " person_role WRITE, names WRITE, ");
349 else
350 for (i=0; tables[tr->class_type][i] != NULL; i++)
351 g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
352
353 for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
354 g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
355
356 g_string_sprintfa(query, " last WRITE, history WRITE, transaction_rec WRITE ");
357
358 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
359
360
361 /* Perform first phase - deletions */
362 UD_commit_I(tr);
363 /* checkpoint this step */
364 CP_COMMIT_I_PASSED(tr->action); TR_update_status(tr);
365 /* Perform first phase - updates */
366 UD_commit_II(tr);
367 /* checkpoint this step */
368 CP_COMMIT_II_PASSED(tr->action); TR_update_status(tr);
369
370 /* Unlock all tables */
371 g_string_sprintf(query, "UNLOCK TABLES ");
372 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
373
374 /* Update radix tree for route, inetnum and inaddr-arpa domain*/
375 err = UD_update_rx(tr, RX_OPER_CRE);
376
377 g_string_free(query, TRUE);
378 return(err);
379 } /* commit() */
380
381 /************************************************************
382 * int UD_check_ref() *
383 * *
384 * Checks if the object to be deleted is referenced from *
385 * anywhere *
386 * *
387 * 0 - go ahead *
388 * -1 - deletion will compromise ref.integrity *
389 * Result is also reflected in tr->succeeded *
390 ************************************************************/
391 int UD_check_ref(Transaction_t *tr)
/* [<][>][^][v][top][bottom][index][help] */
392 {
393 GString *query;
394 int i;
395 long ref_id;
396 long num_rec;
397
398 char sobject_id[STR_M];
399 char *sql_str;
400
401 /* Try to allocate g_string. Return on error */
402 if ((query = g_string_sized_new(STR_XXL)) == NULL){
403 ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
404 tr->succeeded=0;
405 tr->error|=ERROR_U_MEM;
406 die;
407 }
408
409
410 /* Check for referential integrity of deletion */
411
412 sprintf(sobject_id, "%ld", tr->object_id);
413
414 switch(tr->class_type){
415 case C_PN:
416 case C_RO:
417
418 /* Check that this person/role object is not referenced */
419
420 for (i=0; t_ipn[i] != NULL; i++) {
421 /* Calculate number of references */
422 sql_str= get_field_str(tr->sql_connection, "COUNT(*)", t_ipn[i], "pe_ro_id", sobject_id, NULL);
423 if(sql_str) {
424 num_rec = atol(sql_str); free(sql_str);
425 ref_id=tr->object_id;
426 /* Check if it is a self reference (for role objects) */
427 if(num_rec==1) {
428 sql_str= get_field_str(tr->sql_connection, "object_id", t_ipn[i], "pe_ro_id", sobject_id, NULL);
429 if(sql_str) {
430 ref_id = atol(sql_str); free(sql_str);
431 } else {
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); 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); 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); 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); 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