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.23 $
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 for (i=0; tables[tr->class_type][i] != NULL; i++)
348 g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
349 } else { /* mntner and role are special cases */
350 g_string_sprintfa(query, " mntner WRITE, person_role WRITE, ");
351 }
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 long timestamp;
398
399 char sobject_id[STR_M];
400 char *sql_str;
401 int sql_err;
402
403 /* Try to allocate g_string. Return on error */
404 if ((query = g_string_sized_new(STR_XXL)) == NULL){
405 ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
406 tr->succeeded=0;
407 tr->error|=ERROR_U_MEM;
408 die;
409 }
410
411
412 /* Check for referential integrity of deletion */
413
414 sprintf(sobject_id, "%ld", tr->object_id);
415
416 switch(tr->class_type){
417 case C_PN:
418 case C_RO:
419
420 /* Check that this person/role object is not referenced */
421
422 for (i=0; t_ipn[i] != NULL; i++) {
423 /* Calculate number of references */
424 sql_str= get_field_str(tr->sql_connection, "COUNT(*)", t_ipn[i], "pe_ro_id", sobject_id, NULL);
425 if(sql_str) {
426 num_rec = atol(sql_str); free(sql_str);
427 ref_id=tr->object_id;
428 /* Check if it is a self reference (for role objects) */
429 if(num_rec==1) {
430 sql_str= get_field_str(tr->sql_connection, "object_id", t_ipn[i], "pe_ro_id", sobject_id, NULL);
431 if(sql_str) {
432 ref_id = atol(sql_str); free(sql_str);
433 } else {
434 tr->succeeded=0; tr->error |= ERROR_U_DBS; break;
435 }
436 }
437 /* If there are references (and not the only self reference) we cannot delete */
438 if((num_rec>1) || (ref_id!=tr->object_id)) {
439 g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, t_ipn[i]);
440 tr->succeeded=0; tr->error |= ERROR_U_OBJ;
441 }
442 } else {
443 /* SQL error occured */
444 tr->succeeded=0; tr->error |= ERROR_U_DBS;
445 g_string_sprintfa(tr->error_script,"E[%d][%s]:%s\n", ERROR_U_DBS, t_ipn[i], SQ_error(tr->sql_connection));
446 }
447 }
448
449 /* Check that this person/role object is not referenced by name (legacy stuff) */
450 /* But allow overriding this check in NRTM mode and with override_integrity */
451 if(IS_DUMMY_ALLOWED(tr->mode))break;
452
453 for (i=0; t_ipn[i] != NULL; i++) {
454 /* Calculate number of references */
455
456 g_string_sprintf(query, "SELECT COUNT(*) FROM %s, person_role "
457 "WHERE person_role.object_id=%s.pe_ro_id "
458 "AND person_role.nic_hdl='%s' ", t_ipn[i], t_ipn[i], tr->save);
459
460 sql_str= get_qresult_str(tr->sql_connection, query->str);
461 if(sql_str) {
462 num_rec = atol(sql_str); free(sql_str);
463 /* If there are references (no self reference is possible in this case) we cannot delete */
464 if(num_rec>0) {
465 g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, t_ipn[i]);
466 tr->succeeded=0; tr->error |= ERROR_U_OBJ;
467 }
468 } else {
469 /* SQL error occured */
470 tr->succeeded=0; tr->error |= ERROR_U_DBS;
471 g_string_sprintfa(tr->error_script,"E[%d][%s]:%s\n", ERROR_U_DBS, t_ipn[i], SQ_error(tr->sql_connection));
472 }
473 }
474
475 break;
476
477 case C_MT:
478
479 /* Check that this mntner object is not referenced */
480
481 for (i=0; t_imt[i] != NULL; i++) {
482 /* Calculate number of references */
483 sql_str= get_field_str(tr->sql_connection, "COUNT(*)", t_imt[i], "mnt_id", sobject_id, NULL);
484 if(sql_str) {
485 num_rec = atol(sql_str); free(sql_str);
486 ref_id=tr->object_id;
487 /* Check if it is a self reference */
488 if(num_rec==1) {
489 sql_str= get_field_str(tr->sql_connection, "object_id", t_imt[i], "mnt_id", sobject_id, NULL);
490 if(sql_str) {
491 ref_id = atol(sql_str); free(sql_str);
492 } else {
493 tr->succeeded=0; tr->error |= ERROR_U_DBS; break;
494 }
495 }
496 /* If there are references (and not the only self reference) we cannot delete */
497 if((num_rec>1) || (ref_id!=tr->object_id)) {
498 g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, t_imt[i]);
499 tr->succeeded=0; tr->error |= ERROR_U_OBJ;
500 }
501 } else {
502 tr->succeeded=0; tr->error |= ERROR_U_DBS;
503 }
504 }
505 break;
506
507 case C_RS:
508 case C_AS:
509 /* Check that this set object is not referenced */
510 /* Calculate number of references */
511 sql_str= get_field_str(tr->sql_connection, "COUNT(*)", "member_of", "set_id", sobject_id, NULL);
512 if(sql_str) {
513 num_rec = atol(sql_str); free(sql_str);
514 /* XXX though set may contain other sets as memebers, */
515 /* there is no member-of attribute in these objects. */
516 /* So no self-reference is possible */
517 if(num_rec!=0) {
518 g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, "member_of");
519 /*tr->succeeded=0; tr->error |= ERROR_U_OBJ;*/
520 /* XXX Do not refuse the transaction but change the object to dummy */
521 /* Update the history table */
522 g_string_sprintf(query, "INSERT history "
523 "SELECT 0, object_id, sequence_id, timestamp, object_type, object, pkey, serial, prev_serial "
524 "FROM last "
525 "WHERE object_id=%ld ", tr->object_id);
526
527
528 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
529 if (sql_err) {
530 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
531 tr->succeeded=0;
532 tr->error |=ERROR_U_DBS;
533 die;
534 }
535
536 /* insert new version into the last */
537 timestamp=time(NULL);
538
539 /* update the main table */
540 g_string_sprintf(query, "UPDATE %s SET dummy=1 WHERE object_id=%ld ", DF_get_class_sql_table(tr->class_type), tr->object_id);
541
542 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
543 if (sql_err) {
544 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
545 tr->succeeded=0;
546 tr->error |= ERROR_U_DBS;
547 die;
548 }
549
550 /* empty the contents, but leave in the table to prevent re-use of object_id */
551 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);
552
553 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
554 if (sql_err) {
555 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
556 tr->succeeded=0;
557 tr->error |= ERROR_U_DBS;
558 die;
559 }
560 return(0);
561
562 }
563 } else {
564 tr->succeeded=0; tr->error |= ERROR_U_DBS;
565 }
566 break;
567
568 default:
569 break;
570 }
571
572 g_string_free(query, TRUE);
573
574 /* Check if we have passed referential integrity check */
575 if(tr->succeeded) return(0); else return(-1);
576
577 }
578
579 /************************************************************
580 * int UD_delete() *
581 * *
582 * Deletes the object *
583 * *
584 * It deletes the object from all relevant tables.
585 * Then it updates the radix tree for routes, inetnums
586 * and rev.domains *
587 * *
588 ************************************************************/
589 int UD_delete(Transaction_t *tr)
/* [<][>][^][v][top][bottom][index][help] */
590 {
591 GString *query;
592 int err=0;
593 int i;
594 long timestamp;
595 int sql_err;
596
597 /* Try to allocate g_string. Return on error */
598 if ((query = g_string_sized_new(STR_XXL)) == NULL){
599 ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
600 tr->succeeded=0;
601 tr->error|=ERROR_U_MEM;
602 die;
603 }
604
605
606 /* Lock all relevant tables */
607 g_string_sprintf(query, "LOCK TABLES ");
608
609 /* we need to lock tables for mntner and role differently, otherwise there will be duplicates (names names, etc.)*/
610 if((tr->class_type!=C_MT) && (tr->class_type!=C_RO)){
611 g_string_sprintfa(query, " %s WRITE,", DF_get_class_sql_table(tr->class_type));
612
613 for (i=0; tables[tr->class_type][i] != NULL; i++)
614 g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
615 } else { /* mntner and role are special cases */
616 g_string_sprintfa(query, " mntner WRITE, person_role WRITE, ");
617 }
618
619 for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
620 g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
621
622 g_string_sprintfa(query, " last WRITE, history WRITE ");
623
624 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
625 if (sql_err) {
626 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
627 tr->succeeded=0;
628 tr->error |=ERROR_U_DBS;
629 die;
630 }
631 /* Update the history table */
632 /* XXX Crash recovery: */
633 /* If history was not updated - we will create a record */
634 /* If history was already updated but last wasn't - we will just replace the record */
635 /* If history and last were already updated - we will have an empty query - 0 rows should be affected */
636 g_string_sprintf(query, "REPLACE history "
637 "SELECT 0, object_id, sequence_id, timestamp, object_type, object, pkey, serial, prev_serial "
638 "FROM last "
639 "WHERE object_id=%ld AND sequence_id=%ld ", tr->object_id, tr->sequence_id);
640 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
641 if (sql_err) {
642 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
643 tr->succeeded=0;
644 tr->error |=ERROR_U_DBS;
645 die;
646 }
647
648 /* Delete records from the leaf and aux tables */
649 for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
650 g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", tables[tr->class_type][i], tr->object_id);
651 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
652 /* ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s query (delete): %s\n", UD_TAG, query->str);*/
653 if (sql_err) {
654 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
655 tr->succeeded=0;
656 tr->error |=ERROR_U_DBS;
657 die;
658 }
659 }
660
661
662
663 /* Process the MAIN table */
664 g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", DF_get_class_sql_table(tr->class_type), tr->object_id);
665
666
667 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
668 if (sql_err) {
669 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
670 tr->succeeded=0;
671 tr->error |=ERROR_U_DBS;
672 die;
673 }
674
675
676 /* insert new version into the last */
677 timestamp=time(NULL);
678
679 /* empty the contents, but leave in the table to restrict re-use of object_id */
680 /* XXX change sequence_id=0 so it is easy to say that the object was deleted */
681 g_string_sprintf(query, "UPDATE last SET object='', timestamp=%ld, sequence_id=0 WHERE object_id=%ld ", timestamp, tr->object_id);
682
683 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
684 if (sql_err) {
685 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
686 tr->succeeded=0;
687 tr->error |= ERROR_U_DBS;
688 die;
689 }
690
691
692
693 /* Unlock all tables */
694 g_string_sprintf(query, "UNLOCK TABLES ");
695 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
696 if (sql_err) {
697 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
698 tr->succeeded=0;
699 tr->error |= ERROR_U_DBS;
700 die;
701 }
702
703
704 g_string_free(query, TRUE);
705
706 return(err);
707
708 } /* delete() */
709
710
711
712 /* Do more in the forest
713 * Update radix tree for route and inetnum
714 */
715
716 int UD_update_rx(Transaction_t *tr, rx_oper_mt mode)
/* [<][>][^][v][top][bottom][index][help] */
717 {
718 rp_upd_pack_t *packptr = tr->packptr;
719 int err=0;
720
721
722 if(!IS_STANDALONE(tr->mode)) { /* only if server */
723
724
725 /* Only for these types of objects and only if we have collected data (tr->save != NULL) */
726 if( ( (tr->class_type==C_RT)
727 || (tr->class_type==C_IN)
728 || (tr->class_type==C_I6)
729 || (tr->class_type==C_DN))) {
730 /* Collect some data for radix tree and NH repository update for deletes*/
731 if(mode == RX_OPER_DEL)g_slist_foreach((tr->object)->attributes, get_rx_data, tr);
732
733 /* Except for regular domains we need to update radix tree */
734 if(ACT_UPD_RX(tr->action)){
735 packptr->key = tr->object_id;
736 if( RP_pack_node(mode, packptr, tr->source_hdl) == RX_OK ) {
737 err = 0;
738 } else {
739 err = (-1);
740 ER_perror(FAC_UD, UD_BUG, "cannot update radix tree\n");
741 die;
742 }
743 } /* update radix tree */
744 }
745 }
746 return(err);
747 }
748
749
750