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