1 | /*************************************** 2 | 3 | $Revision: 1.40 $ 4 | 5 | Core functions for update lower layer 6 | 7 | Status: NOT REVUED, NOT TESTED 8 | 9 | Author(s): Chris Ottrey, Andrei Robachevsky 10 | 11 | ******************/ /****************** 12 | Modification History: 13 | andrei (17/01/2000) Created. 14 | ******************/ /****************** 15 | Copyright (c) 2000 RIPE NCC 16 | 17 | All Rights Reserved 18 | 19 | Permission to use, copy, modify, and distribute this software and its 20 | documentation for any purpose and without fee is hereby granted, 21 | provided that the above copyright notice appear in all copies and that 22 | both that copyright notice and this permission notice appear in 23 | supporting documentation, and that the name of the author not be 24 | used in advertising or publicity pertaining to distribution of the 25 | software without specific, written prior permission. 26 | 27 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 28 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL 29 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY 30 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 31 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 32 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 33 | ***************************************/ 34 | #include "ud.h" 35 | #include "ud_int.h" 36 | #include "ud_tr.h" 37 | 38 | #include <sys/types.h> 39 | #include <signal.h> 40 | #include <time.h> 41 | 42 | static int perform_update(Transaction_t *tr); 43 | 44 | static int perform_create(Transaction_t *tr); 45 | 46 | static void each_attribute_process(void *element_data, void *tr_ptr); 47 | 48 | static void update_attr(Attribute_t *attr, Transaction_t *tr); 49 | 50 | static int create_dummy(Attribute_t *attr, Transaction_t *tr); 51 | 52 | static int auth_member_of(Attribute_t *attr, Transaction_t *tr); 53 | 54 | /*************************************************** 55 | * char *s_split(char *line) * 56 | * * 57 | * Consequently returns words of the 'line' * 58 | * When there are no words it returns NULL * 59 | * You need to retreive all words ! * 60 | * * 61 | * NB This function damages 'line' replacing * 62 | * whitespace with '\0' * 63 | * *************************************************/ 64 | #define ATTR_DELIMITERS " ," 65 | 66 | 67 | /********************************************************** 68 | * Attribute expansion/conversion functions * 69 | ***********************************************************/ 70 | /* Convert ifaddr attribute into numbers */ 71 | er_ret_t convert_if(char *avalue, unsigned int *pif_address) 72 | { 73 | char *delim=avalue; 74 | ip_addr_t ip_addr; 75 | er_ret_t ret; 76 | 77 | /*XXX if ((delim=index(avalue, ' '))!=NULL) *delim='\0'; */ 78 | while((*delim) && (!isspace((int)*delim))) { 79 | delim++; 80 | } 81 | *delim='\0'; 82 | 83 | ret=IP_addr_a2v4(avalue, &ip_addr, pif_address ); 84 | return(ret); 85 | } 86 | 87 | 88 | /* Convert refer attribute. Free host after use ! */ 89 | char *convert_rf(char *avalue, int *type, int *port) 90 | { 91 | char *delim, *token; 92 | char buff[STR_M]; 93 | char *host; 94 | 95 | host=NULL; 96 | strcpy(buff, avalue); 97 | g_strchug(buff); 98 | /*XXX delim=index(buff, ' '); */ 99 | delim=buff; 100 | while((*delim) && (!isspace((int)*delim))) { 101 | delim++; 102 | } 103 | if (*delim)*delim='\0'; else return(NULL); 104 | delim++; 105 | 106 | /* convert the type */ 107 | if(g_strcasecmp(buff, S_RIPE)==0)*type=RF_RIPE; 108 | else if(g_strcasecmp(buff, S_INTERNIC)==0)*type=RF_INTERNIC; 109 | else if(g_strcasecmp(buff, S_SIMPLE)==0)*type=RF_SIMPLE; 110 | else if(g_strcasecmp(buff, S_CLIENTADDERSS)==0)*type=RF_CLIENTADDRESS; 111 | 112 | token=delim; 113 | g_strchug(token); 114 | /*XXX delim=index(token, ' '); */ 115 | delim=token; 116 | while((*delim) && (!isspace((int)*delim))) { 117 | delim++; 118 | } 119 | 120 | if(*delim){ 121 | *delim='\0'; 122 | delim++; 123 | } 124 | /* convert the hostname */ 125 | host = g_strdup(token); 126 | 127 | /* convert port number */ 128 | if(*delim){ 129 | token=delim; 130 | *port = atoi(token); 131 | if (*port==0) *port=RF_DEF_PORT; /* default port number*/ 132 | } else *port=RF_DEF_PORT; 133 | return(host); 134 | } 135 | 136 | 137 | /* Convert AS# into integer */ 138 | static int convert_as(char *as) 139 | { 140 | char *ptr; 141 | ptr=as; 142 | while((*ptr) && (!isdigit((int)*ptr))) ptr++; 143 | return(atoi(ptr)); 144 | } 145 | 146 | /* Convert AS range (AS4321 - AS5672) into numbers */ 147 | int convert_as_range(const char *as_range, int *begin, int *end) 148 | { 149 | char *range; 150 | char *token; 151 | 152 | range=g_strdup(as_range); 153 | token=range; 154 | *begin=convert_as(strsep(&token, "-")); 155 | *end=convert_as(token); 156 | free(range); 157 | return(0); 158 | } 159 | 160 | /* Convert time in ASCII format (19991224) into time_t unix time */ 161 | time_t convert_time(char *asc_time) 162 | { 163 | struct tm tm; 164 | char buf[STR_S]; 165 | char *ptr; 166 | 167 | 168 | bzero(&tm, sizeof(tm)); 169 | 170 | strncpy(buf, asc_time, 4); ptr=buf+4; *ptr='\0'; 171 | tm.tm_year = atoi(buf) - 1900; 172 | 173 | strncpy(buf, (asc_time+4), 2); ptr=buf+2; *ptr='\0'; 174 | tm.tm_mon = atoi(buf) - 1; 175 | 176 | strncpy(buf, (asc_time+6), 2); ptr=buf+2; *ptr='\0'; 177 | tm.tm_mday = atoi(buf); 178 | 179 | return(mktime(&tm)); 180 | 181 | } 182 | 183 | 184 | /************************************************************ 185 | * char *get_set_name() * 186 | * * 187 | * Returns set name for the specified object class * 188 | * * 189 | * **********************************************************/ 190 | static char *get_set_name(C_Type_t class_type) 191 | { 192 | switch(class_type){ 193 | case C_RT: return("route_set"); 194 | case C_AN: return("as_set"); 195 | case C_IR: return("rtr_set"); 196 | default: return(NULL); 197 | } 198 | } 199 | 200 | 201 | /************************************************************ 202 | * long get_object_id() * 203 | * Queries the database for an object. * 204 | * For constructing a query uses each_primary_key_select() * 205 | * * 206 | * Returns: * 207 | * >0 - object exists, returns object_id * 208 | * 0 - object does not exist * 209 | * -1 - error (f.e. more than one object with the same PK) * 210 | * Error code is stored in tr->error * 211 | * * 212 | * **********************************************************/ 213 | long get_object_id(Transaction_t *tr) 214 | { 215 | Object_t *obj; 216 | SQ_result_set_t *sql_result; 217 | SQ_row_t *sql_row; 218 | char *sql_str; 219 | long object_id=0; 220 | int sql_err; 221 | 222 | obj=tr->object; 223 | 224 | if ((tr->query = g_string_sized_new(STR_XL)) == NULL){ 225 | ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n"); 226 | tr->succeeded=0; 227 | tr->error |= ERROR_U_MEM; 228 | die; 229 | } 230 | 231 | /* compose query */ 232 | g_string_sprintf(tr->query, "SELECT object_id FROM %s WHERE",DF_get_class_sql_table(obj->type)); 233 | /* add all primary keys */ 234 | g_slist_foreach(obj->attributes, ud_each_primary_key_select, tr); 235 | /* truncate the last ' AND '*/ 236 | g_string_truncate(tr->query, (tr->query->len) - 4); 237 | 238 | /* execute query */ 239 | ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, tr->query->str); 240 | sql_err=SQ_execute_query(tr->sql_connection, tr->query->str, &sql_result); 241 | 242 | /* in case of an error copy error code and return */ 243 | if(sql_err) { 244 | ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), tr->query->str); 245 | tr->succeeded=0; 246 | tr->error |= ERROR_U_DBS; 247 | die; 248 | } 249 | g_string_free(tr->query, TRUE); 250 | 251 | /* Fetch the row */ 252 | if ((sql_row = SQ_row_next(sql_result)) != NULL) { 253 | /* Object exists */ 254 | #define OBJECT_ID 0 255 | sql_str = SQ_get_column_string(sql_result, sql_row, OBJECT_ID); 256 | if (sql_str != NULL) { 257 | object_id = atol(sql_str); 258 | free(sql_str); 259 | } 260 | 261 | /* We must process all the rows of the result */ 262 | /* otherwise we'll have them as part of the next qry */ 263 | while ( (sql_row = SQ_row_next(sql_result)) != NULL) object_id=-1; 264 | } else 265 | object_id=0; /* object does not exist*/ 266 | 267 | SQ_free_result(sql_result); 268 | return(object_id); 269 | } 270 | 271 | /************************************************************ 272 | * get_minmax_id() * 273 | * * 274 | * Returns the min or max ID of the table * 275 | * * 276 | * Returns: * 277 | * min (max=0) or max (max=1) ID * 278 | * -1 in case of an error * 279 | * * 280 | * * 281 | *************************************************************/ 282 | long get_minmax_id(SQ_connection_t *sql_connection, char *id_name, char *tbl_name, int max) 283 | { 284 | char query[STR_M]; 285 | SQ_result_set_t *sql_result; 286 | SQ_row_t *sql_row; 287 | char *sql_str; 288 | long id; 289 | char *minmax; 290 | int sql_err; 291 | 292 | if(max==1)minmax="max"; else minmax="min"; 293 | 294 | sprintf(query, "SELECT %s(%s) FROM %s ", minmax, id_name, tbl_name); 295 | 296 | ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query); 297 | sql_err = SQ_execute_query(sql_connection, query, &sql_result); 298 | 299 | if(sql_err) { 300 | ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(sql_connection), query); 301 | die; 302 | } 303 | 304 | 305 | if ((sql_row = SQ_row_next(sql_result)) != NULL) { 306 | sql_str = SQ_get_column_string(sql_result, sql_row, 0); 307 | 308 | /* We must process all the rows of the result,*/ 309 | /* otherwise we'll have them as part of the next qry */ 310 | while ( (sql_row = SQ_row_next(sql_result)) != NULL) { 311 | ER_perror(FAC_UD, UD_SQL, "duplicate PK [%s]\n", query); 312 | die; 313 | if(sql_str)free(sql_str); sql_str=NULL; 314 | } 315 | } 316 | else sql_str=NULL; 317 | 318 | if(sql_result){ SQ_free_result(sql_result); sql_result=NULL; } 319 | 320 | if(sql_str) { 321 | id = atol(sql_str); 322 | free(sql_str); 323 | } 324 | else id=-1; 325 | 326 | return(id); 327 | 328 | } 329 | 330 | 331 | /************************************************************ 332 | * get_qresult_str() * 333 | * * 334 | * Returns string containing query result * 335 | * * 336 | * * 337 | * Returns: * 338 | * String containing the result.Needs to be freed after use * 339 | * NULL in case of an error * 340 | * - SQL error * 341 | * - if query returns more than one string (row) * 342 | * * 343 | *************************************************************/ 344 | char *get_qresult_str(SQ_connection_t *sql_connection, char *query) 345 | { 346 | SQ_result_set_t *sql_result; 347 | SQ_row_t *sql_row; 348 | char *sql_str; 349 | int sql_err; 350 | 351 | 352 | ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query); 353 | sql_err=SQ_execute_query(sql_connection, query, &sql_result); 354 | 355 | if(sql_err) { 356 | ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(sql_connection), query); 357 | die; 358 | } 359 | 360 | 361 | if ((sql_row = SQ_row_next(sql_result)) != NULL) { 362 | sql_str = SQ_get_column_string(sql_result, sql_row, 0); 363 | 364 | /* We must process all the rows of the result,*/ 365 | /* otherwise we'll have them as part of the next qry */ 366 | while ( (sql_row = SQ_row_next(sql_result)) != NULL) { 367 | ER_perror(FAC_UD, UD_SQL, "duplicate PK [%s]\n", query); 368 | if(sql_str)free(sql_str); sql_str=NULL; 369 | } 370 | } 371 | else sql_str=NULL; 372 | 373 | SQ_free_result(sql_result); 374 | return(sql_str); 375 | } 376 | 377 | 378 | 379 | /************************************************************ 380 | * get_field_str() * 381 | * * 382 | * Returns string containing the field. * 383 | * field - field name to be retrieved * 384 | * ref_tbl_name - name of the table containing the field * 385 | * ref_name - reference name * 386 | * attr_value - reference value * 387 | * condition - additional condition ( f.e. 'AND dummy=0' * 388 | * * 389 | * Returns: * 390 | * String containing the field. Needs to be freed after use * 391 | * NULL in case of an error * 392 | * * 393 | *************************************************************/ 394 | char *get_field_str(SQ_connection_t *sql_connection, char *field, 395 | char *ref_tbl_name, char *ref_name, 396 | char * attr_value, char *condition) 397 | { 398 | char query[STR_L]; 399 | 400 | sprintf(query, "SELECT %s FROM %s " 401 | "WHERE %s='%s' ", 402 | field, ref_tbl_name, ref_name, attr_value); 403 | if (condition)strcat(query, condition); 404 | 405 | return( get_qresult_str(sql_connection, query)); 406 | 407 | } 408 | 409 | /************************************************************ 410 | * long get_sequence_id(Transaction_t *tr) 411 | * >0 - success 412 | * -1 - sql error 413 | * 414 | * **********************************************************/ 415 | 416 | long get_sequence_id(Transaction_t *tr) 417 | { 418 | char *sql_str; 419 | char str_id[STR_M]; 420 | long sequence_id=-1; 421 | 422 | 423 | sprintf(str_id, "%ld", tr->object_id); 424 | sql_str= get_field_str(tr->sql_connection, "sequence_id", "last", "object_id", str_id, NULL); 425 | if(sql_str) { 426 | sequence_id = atol(sql_str); 427 | free(sql_str); 428 | } 429 | 430 | return(sequence_id); 431 | 432 | } 433 | 434 | 435 | /************************************************************ 436 | * long get_ref_id(char *ref_tbl_name, char *ref_name, char * attr_value) 437 | * >0 - success 438 | * -1 - sql error 439 | * 440 | * **********************************************************/ 441 | 442 | static long get_ref_id(Transaction_t *tr, char *ref_tbl_name, char *ref_name, char * attr_value, char *condition) 443 | { 444 | char *sql_str; 445 | long ref_id=-1; 446 | 447 | sql_str= get_field_str(tr->sql_connection, "object_id", ref_tbl_name, ref_name, attr_value, condition); 448 | if(sql_str) { 449 | ref_id = atol(sql_str); 450 | free(sql_str); 451 | } 452 | return(ref_id); 453 | } 454 | 455 | 456 | /************************************************************ 457 | * int isdummy() 458 | * 459 | * Returns 1 if the object in question is a dummy, 460 | * otherwise returns 0. 461 | * 462 | * In case of error: 463 | * -1 - sql error or object does not exist 464 | * 465 | ***********************************************************/ 466 | 467 | int isdummy(Transaction_t *tr) 468 | { 469 | char *sql_str; 470 | char str_id[STR_M]; 471 | int object_type=-1; 472 | 473 | sprintf(str_id, "%ld", tr->object_id); 474 | sql_str= get_field_str(tr->sql_connection, "object_type", "last", "object_id", str_id, NULL); 475 | if(sql_str) { 476 | object_type = atoi(sql_str); 477 | free(sql_str); 478 | } 479 | 480 | if (object_type==-1) { 481 | ER_perror(FAC_UD, UD_SQL, "cannot get object type\n"); 482 | die; 483 | } 484 | if (object_type==DUMMY_TYPE) return(1); 485 | else return(0); 486 | 487 | } 488 | 489 | /* it may be either a legacy name reference, or a nic-handle */ 490 | /* we rely on other parsers/syntax checkers, so no surprises */ 491 | /* thus, the check is simple - if there is a space - not a nh */ 492 | static int isnichandle(char *name) 493 | { 494 | char *delim; 495 | 496 | /*XXX if(index(name, ' ')) return(0); 497 | else return(1); */ 498 | delim=name; 499 | while((*delim) && (!isspace((int)*delim))) { 500 | delim++; 501 | } 502 | if(*delim) return(0); 503 | else return(1); 504 | } 505 | 506 | 507 | /************************************************************ 508 | * process_reverse_domain() * 509 | * * 510 | * Tries to insert additional data for reverse domains * 511 | * This data includes prefix and perfix length for reverse * 512 | * delegation block. It is stored in inaddr_arpa table for * 513 | * IPv4 and ip6int table for IPv6 address spaces * 514 | * * 515 | * Returns: * 516 | * 0 success * 517 | * -1 sql error * 518 | * * 519 | *************************************************************/ 520 | 521 | static int process_reverse_domain(Transaction_t *tr, 522 | ip_prefix_t *prefptr, 523 | int op) 524 | { 525 | unsigned prefix, prefix_length; /* ipv4 */ 526 | ip_v6word_t msb, lsb; /* ipv6 */ 527 | char query[STR_L]; 528 | int num; 529 | int sql_err; 530 | 531 | 532 | if( IP_pref_b2_space(prefptr) == IP_V4 ) { /* ipv4 */ 533 | if(op==0) { /* insert record */ 534 | IP_revd_b2v4(prefptr, &prefix, &prefix_length); 535 | sprintf(query, "INSERT INTO inaddr_arpa SET thread_id=%d, object_id=%ld, prefix=%u, prefix_length=%d ", 536 | tr->thread_ins, tr->object_id, prefix, prefix_length); 537 | } 538 | else { 539 | /* update record */ 540 | sprintf(query, "UPDATE inaddr_arpa SET thread_id=%d WHERE object_id=%ld ", 541 | tr->thread_upd, tr->object_id); 542 | } 543 | } 544 | else { /* ipv6 */ 545 | if(op==0) { /* insert record */ 546 | IP_revd_b2v6(prefptr, &msb, &lsb, &prefix_length); 547 | sprintf(query, "INSERT INTO ip6int SET thread_id=%d, object_id=%ld, msb='%llu', lsb='%llu', prefix_length=%d ", 548 | tr->thread_ins, tr->object_id, msb, lsb, prefix_length); 549 | } 550 | else { 551 | /* update record */ 552 | sprintf(query, "UPDATE ip6int SET thread_id=%d WHERE object_id=%ld ", 553 | tr->thread_upd, tr->object_id); 554 | } 555 | } 556 | 557 | ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query); 558 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL); 559 | num = SQ_get_affected_rows(tr->sql_connection); 560 | 561 | /* Check for errors */ 562 | if (sql_err) { 563 | ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query); 564 | die; 565 | } 566 | /* If nothing was affected then WHERE clause returned nothing - DB error */ 567 | if(num == 0) { 568 | ER_perror(FAC_UD, UD_SQL, "insert inaddr had no effect [%s]\n", query); 569 | die; 570 | } 571 | return(0); 572 | } 573 | 574 | #define insert_reverse_domain(tr, pr) process_reverse_domain(tr, pr, 0) 575 | #define update_reverse_domain(tr, pr) process_reverse_domain(tr, pr, 1) 576 | 577 | 578 | /************************************************************ 579 | * auth_member_of() * 580 | * * 581 | * Function that checks the authorization for membership * 582 | * (i.e. if the object is authorized to be a memeber by * 583 | * mbrs-by-ref attribute of the set is refers by member-of * 584 | * attribute). * 585 | * First checks if 'mbrs-by-ref: ANY' * 586 | * If not then checks that maintner referenced by * 587 | * mbrs-by-ref attribute of the set is the one in mnt-by. * 588 | * * 589 | * Returns: * 590 | * 0 success * 591 | * 1 not allowed * 592 | * -1 SQL error * 593 | * * 594 | *************************************************************/ 595 | static int auth_member_of(Attribute_t *attr, Transaction_t *tr) 596 | { 597 | GString *query; 598 | char *set_name; 599 | char *qresult; 600 | 601 | /* Check if set has mbrs_by_ref==ANY 602 | In such case mbrs_by_ref.mnt_id==0 603 | */ 604 | 605 | if ((query = g_string_sized_new(STR_XL)) == NULL){ 606 | tr->succeeded=0; 607 | tr->error |= ERROR_U_MEM; 608 | ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n"); 609 | die; 610 | } 611 | 612 | set_name = get_set_name(tr->class_type); 613 | /* ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s set name retrieved: %s\n", UD_TAG, set_name); */ 614 | 615 | /* Check if the set protects itself with mbrs-by-ref attribute */ 616 | g_string_sprintf(query,"SELECT COUNT(*) FROM mbrs_by_ref, %s " 617 | "WHERE mbrs_by_ref.object_id=%s.object_id " 618 | "AND %s.%s='%s' ", 619 | set_name, set_name, set_name, set_name, attr->value); 620 | 621 | qresult = get_qresult_str(tr->sql_connection, query->str); 622 | /* should be '0' if there is no mbrs-by-ref attribute */ 623 | if (strcmp(qresult, "0")==0){ 624 | /* there is no mbrs-by-ref attribute - so we cannot go ahead */ 625 | ER_dbg_va(FAC_UD, ASP_UD_OBJ, "[%ld] membership by reference is not allowed (no mbrs-by-ref) [%d:%s]", tr->transaction_id, attr->type, attr->value); 626 | g_string_free(query, TRUE); 627 | return(1); 628 | } 629 | else free(qresult); 630 | 631 | /* Check if membership is protected by the keyword "ANY" */ 632 | /* There is a dummy mntmer object in the database corresponding to "ANY" */ 633 | /* Its object_id==0 */ 634 | /* EXAMPLE: 635 | 636 | SELECT route_set.object_id 637 | FROM mbrs_by_ref, route_set 638 | WHERE mbrs_by_ref.object_id=route_set.object_id 639 | AND route_set.route_set=<setname> 640 | AND mbrs_by_ref.mnt_id=0 641 | */ 642 | g_string_sprintf(query,"SELECT %s.object_id FROM mbrs_by_ref, %s " 643 | "WHERE mbrs_by_ref.object_id=%s.object_id " 644 | "AND %s.%s='%s' AND mbrs_by_ref.mnt_id=0 ", 645 | set_name, set_name, set_name, set_name, set_name, attr->value); 646 | 647 | qresult = get_qresult_str(tr->sql_connection, query->str); 648 | /* if such record exists - go ahead */ 649 | if(qresult) { 650 | free(qresult); 651 | g_string_free(query, TRUE); 652 | return(0); 653 | } 654 | 655 | /* Now check if our mnt_by belongs to mbrs_by_ref list of the set */ 656 | /* we search only mnt_by.thread_id!=0 to check against new/updated mnt-by attribute */ 657 | g_string_sprintf(query, "SELECT mbrs_by_ref.object_id FROM %s, mbrs_by_ref, mnt_by " 658 | "WHERE mbrs_by_ref.mnt_id=mnt_by.mnt_id " 659 | "AND mnt_by.object_id=%ld " 660 | "AND %s.object_id=mbrs_by_ref.object_id " 661 | "AND %s.%s='%s' " 662 | "AND ( mnt_by.thread_id=%d OR mnt_by.thread_id=%d ) ", 663 | set_name, tr->object_id, set_name, set_name, set_name, attr->value, tr->thread_upd, tr->thread_ins); 664 | 665 | qresult = get_qresult_str(tr->sql_connection, query->str); 666 | /* If our mntner is listed (non-empty result) membership is authorized */ 667 | if (qresult) { 668 | free(qresult);g_string_free(query, TRUE); 669 | return(0); 670 | } else { 671 | ER_dbg_va(FAC_UD, ASP_UD_OBJ, "[%ld] membership by reference is not autorized [%d:%s]", tr->transaction_id, attr->type, attr->value); 672 | g_string_free(query, TRUE); 673 | return(1); 674 | } 675 | }/* auth_member_of() */ 676 | 677 | 678 | /************************************************************ 679 | * create_dummy() * 680 | * * 681 | * Function that creates a dummy object (that is one that * 682 | * is referenced from an object but does not * 683 | * exist in the database). * 684 | * Dummy object exists only in relevant main and 'last' * 685 | * tables. Its creation is controlled by tr->dummy_allowed. * 686 | * Queries for the dummies are defined in Dummy[] array. * 687 | * * 688 | * Returns: * 689 | * 0 success * 690 | * 1 no rf integrity and dummy not allowed * 691 | * -1 SQL error * 692 | * * 693 | *************************************************************/ 694 | static int create_dummy(Attribute_t *attr, Transaction_t *tr) 695 | { 696 | const char *query_fmt; 697 | long dummy_id; 698 | char query[STR_L]; 699 | int result=0; 700 | char *set_name; 701 | char *p_name; 702 | int query_type; 703 | long timestamp; 704 | char str_id[STR_M]; 705 | gchar *attr_value=NULL; 706 | int sql_err; 707 | char *token=NULL; 708 | 709 | query_fmt = DF_get_dummy_query(attr->type); 710 | if (strcmp(query_fmt, "") == 0) { 711 | ER_perror(FAC_UD, UD_BUG, "empty query string\n"); 712 | die; 713 | } 714 | 715 | /* We allow creating dummy sets in any mode */ 716 | /* For others attributes return if we are in protected mode */ 717 | if ((attr->type!=A_MO) && (!IS_DUMMY_ALLOWED(tr->mode))) return(1); 718 | 719 | /* Insert dummy in the last table */ 720 | /* Calculate the object_id - should be max+1 */ 721 | dummy_id = SQ_get_max_id(tr->sql_connection, "object_id", "last") +1; 722 | /* Record dummy's object_id, it'll be needed in commit/rollback */ 723 | tr->dummy_id[tr->ndummy]=dummy_id; tr->ndummy++; 724 | 725 | /* Update the TR for crash recovery */ 726 | /* If we crash before actually creating an entry in last */ 727 | /* there should be no harm - later in rollback we will just try to delete nonexistent object */ 728 | TR_update_dummy(tr); 729 | 730 | sprintf(str_id, "%ld", tr->object_id); 731 | timestamp=time(NULL); 732 | sprintf(query, "INSERT INTO last SET thread_id=%d, object_id=%ld, timestamp=%ld, object_type=%d, object='DUMMY for %s'", 733 | tr->thread_ins, dummy_id, timestamp, DUMMY_TYPE, str_id); 734 | 735 | ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query); 736 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL); 737 | 738 | /* Check for errors */ 739 | if (sql_err) { 740 | ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query); 741 | die; 742 | } 743 | 744 | 745 | /* compose the query */ 746 | query_type=DF_get_dummy_query_type(attr->type); 747 | switch (query_type) { 748 | 749 | /* person_role */ 750 | case UD_AX_PR: 751 | sprintf(query, query_fmt, tr->thread_ins, dummy_id, attr->value, DUMMY_TYPE); 752 | break; 753 | 754 | /* maintner */ 755 | case UD_AX_MT: 756 | sprintf(query, query_fmt, tr->thread_ins, dummy_id, attr->value, DUMMY_TYPE); 757 | break; 758 | 759 | /* as_set, route_set */ 760 | case UD_AX_MO: 761 | set_name = get_set_name(tr->class_type); 762 | sprintf(query, query_fmt, set_name, tr->thread_ins, dummy_id, set_name, attr->value); 763 | break; 764 | 765 | default: 766 | ER_perror(FAC_UD, UD_BUG, "query not defined for this type of attribute[%d]\n", attr->type); 767 | die; 768 | break; 769 | } 770 | 771 | ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query); 772 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL); 773 | if (sql_err) { 774 | ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query); 775 | die; 776 | } 777 | 778 | /* for legacy person/role reference (without nic-handle) create records in names table */ 779 | if( (query_type == UD_AX_PR) && (!isnichandle (attr->value)) ){ 780 | /* parse the names */ 781 | /*ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s adding names for dummy\n", UD_TAG);*/ 782 | query_fmt = DF_get_insert_query(A_PN); 783 | attr_value = g_strdup(attr->value); 784 | token = attr_value; 785 | while((p_name=strsep(&token, " \t"))){ 786 | if (*p_name != '\0'){ 787 | sprintf(query, query_fmt, tr->thread_ins, dummy_id, DUMMY_TYPE, p_name); 788 | ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query); 789 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL); 790 | if (sql_err) 791 | if(SQ_errno(tr->sql_connection) != ER_DUP_ENTRY) { 792 | ER_perror(FAC_UD, UD_SQL, "insert dummy names:%s[%s]\n", SQ_error(tr->sql_connection), query); 793 | result=-1; 794 | } 795 | } 796 | } 797 | free(attr_value); 798 | } 799 | return(result); 800 | } 801 | 802 | /************************************************************ 803 | * update_attr() * 804 | * * 805 | * Function that updates an attribute if it already exists. * 806 | * Called from each_attribute_proces() function if it * 807 | * cannot insert the row. * 808 | * Queries for the attributes are defined in Update[] array. * 809 | * * 810 | * Returns: Nothing. Error code is stored in tr->error. * 811 | * * 812 | *************************************************************/ 813 | static void update_attr(Attribute_t *attr, Transaction_t *tr) 814 | { 815 | int num; 816 | const char *query_fmt; 817 | char *set_name; 818 | unsigned int if_address; 819 | char * rf_host; 820 | int rf_port, rf_type; 821 | char *a_value; 822 | int sq_info[3]; 823 | char * condition; 824 | char *sq_error; 825 | char query[STR_XL]; 826 | ip_prefix_t dn_pref; 827 | int sql_err; 828 | char *token; 829 | char *mu_mntner; 830 | 831 | 832 | /* It may be needed to update second attribute stored in the main table, like inetnum, filter-set, etc. */ 833 | if((tr->load_pass!=0)&&(DF_get_update_query_type(attr->type)!=UD_MA_U2)) return; 834 | 835 | /* ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s updating attribute...\n", UD_TAG);*/ 836 | 837 | /* Do some additional processing for reverse domains */ 838 | /* XXX Later we will implement this under UD_MA_DN case */ 839 | if ((attr->type == A_DN) && (IP_revd_a2b(&dn_pref, attr->value)==IP_OK)) { 840 | if(update_reverse_domain(tr, &dn_pref) !=0 ){ 841 | tr->error|=ERROR_U_DBS; 842 | tr->succeeded=0; 843 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" , 844 | ERROR_U_DBS, attr->type, attr->value, SQ_error(tr->sql_connection)); 845 | } 846 | } 847 | 848 | /* get query format string */ 849 | query_fmt = DF_get_update_query(attr->type); 850 | 851 | if (strcmp(query_fmt, "") == 0) return; 852 | 853 | switch (DF_get_update_query_type(attr->type)) { 854 | case UD_MAIN_: sprintf(query, query_fmt, tr->thread_upd, tr->object_id); 855 | break; 856 | case UD_MA_PR: 857 | sprintf(query, query_fmt, tr->thread_upd, tr->class_type, tr->object_id); 858 | break; 859 | case UD_MA_U2: /* save the new value of the attribute for commit*/ 860 | /* this is necessary for filter(filter-set), netname (inet?num), */ 861 | /* local-as(inet-rtr) attributes, as they are another field in the record */ 862 | if((tr->load_pass != 0)){ 863 | /* for fast loader we need to update the field as we have no commit */ 864 | sprintf(query, query_fmt, DF_get_class_sql_table(tr->class_type), 0, attr->value, tr->object_id); 865 | } 866 | else { 867 | tr->save=g_strdup(attr->value); 868 | /* ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s u2 saved [%s]\n", UD_TAG, tr->save); */ 869 | /* update TR for crash recovery */ 870 | TR_update_save(tr); 871 | return; 872 | } 873 | break; 874 | case UD_AX_PR: 875 | /* This is for non-conformant admin-c, etc.*/ 876 | a_value=attr->value; 877 | if(strlen(attr->value)>MAX_NIC_HDL)*(attr->value + MAX_NIC_HDL)='\0'; 878 | 879 | if (!IS_DUMMY_ALLOWED(tr->mode))condition="AND dummy=0 "; else condition=NULL; 880 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 881 | get_ref_id(tr, "person_role", "nic_hdl", attr->value, condition)); 882 | break; 883 | case UD_AX_MT: 884 | if (!IS_DUMMY_ALLOWED(tr->mode))condition="AND dummy=0 "; else condition=NULL; 885 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 886 | get_ref_id(tr, "mntner", "mntner", attr->value, condition)); 887 | break; 888 | case UD_AX_MU: /* for mnt_routes table*/ 889 | a_value=g_strdup(attr->value); 890 | token = a_value; 891 | mu_mntner=strsep(&token, " \t"); 892 | if (!IS_DUMMY_ALLOWED(tr->mode))condition="AND dummy=0 "; else condition=NULL; 893 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 894 | get_ref_id(tr, "mntner", "mntner", mu_mntner, condition)); 895 | free(a_value); 896 | break; 897 | case UD_AX_MO: 898 | set_name = get_set_name(tr->class_type); 899 | /* ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s retrieved set name: %s\n", UD_TAG, set_name);*/ 900 | if (!IS_DUMMY_ALLOWED(tr->mode))condition="AND dummy=0 "; else condition=NULL; 901 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 902 | get_ref_id(tr, set_name, set_name, attr->value, condition)); 903 | break; 904 | case UD_AX_MR: 905 | if ((g_strcasecmp(attr->value, "ANY")==0)) 906 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 907 | get_ref_id(tr, "mntner", "mntner", "ANY",NULL)); 908 | else { 909 | if (!IS_DUMMY_ALLOWED(tr->mode))condition="AND dummy=0 "; else condition=NULL; 910 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 911 | get_ref_id(tr, "mntner", "mntner", attr->value, condition)); 912 | } 913 | break; 914 | case UD_LEAF_: 915 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, attr->value); 916 | break; 917 | case UD_LF_IF: 918 | /* Convert ascii ip -> numeric one */ 919 | convert_if(attr->value, &if_address); 920 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, if_address); 921 | break; 922 | case UD_LF_RF: 923 | rf_host=convert_rf(attr->value, &rf_type, &rf_port); 924 | if(rf_host == NULL) { 925 | tr->error|=ERROR_U_OBJ; 926 | tr->succeeded=0; 927 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:incorrect attribute value\n" , 928 | ERROR_U_OBJ, attr->type, attr->value); 929 | return; 930 | } 931 | else { 932 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, rf_type, rf_host, rf_port); 933 | free(rf_host); 934 | } 935 | break; 936 | case UD_LF_AY: 937 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, convert_time(attr->value)); 938 | break; 939 | default: 940 | tr->error|=ERROR_U_BUG; 941 | tr->succeeded=0; 942 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:no update qry\n" ,ERROR_U_BUG, attr->type, attr->value); 943 | ER_perror(FAC_UD, UD_BUG, "query not defined for this type of attribute:[%d:%s]\n", attr->type, attr->value); 944 | die; 945 | break; 946 | } 947 | /* Execute the query */ 948 | ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query); 949 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL); 950 | if(sql_err) { /* an error occured*/ 951 | /* Error - copy the error condition and return */ 952 | sq_error=SQ_error(tr->sql_connection); 953 | ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", sq_error, query); 954 | tr->error|=ERROR_U_DBS; 955 | tr->succeeded=0; 956 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,ERROR_U_DBS, attr->type, attr->value, sq_error); 957 | die; 958 | } 959 | else { 960 | /* Query OK */ 961 | num = SQ_get_affected_rows(tr->sql_connection); 962 | if(num == 0) { /* check for duplicates*/ 963 | SQ_get_info(tr->sql_connection, sq_info); /* UPDATE ... SET*/ 964 | if ((sq_info[SQL_DUPLICATES]==0) && (sq_info[SQL_MATCHES]==0)) { 965 | /* Condition with zero duplicates and matches may occur when the object is a dummy */ 966 | /* and we are running in protected mode ( dummies are not allowed, tr->dummy==0). */ 967 | /* In such case we will append "AND dummy=0" to the query, which won't */ 968 | /* return a match if the object in question is a dummy */ 969 | ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] dummy prevents update: [%s]", tr->transaction_id, query); 970 | tr->error|=ERROR_U_OBJ; 971 | tr->succeeded=0; 972 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:dummy update\n" ,ERROR_U_OBJ, attr->type, attr->value); 973 | } /* else duplicate entry - silently drop it */ 974 | } 975 | /* For member_of attribute we need to check membership claim in protected mode */ 976 | if ((attr->type == A_MO) && (!IS_DUMMY_ALLOWED(tr->mode))){ 977 | if(auth_member_of(attr, tr)!=0){ 978 | tr->error|=ERROR_U_AUT; 979 | tr->succeeded=0; 980 | ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] membership by reference is not allowed [%d:%s]", tr->transaction_id, attr->type, attr->value); 981 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:membership not allowed\n" ,ERROR_U_AUT, attr->type, attr->value); 982 | } 983 | } 984 | } 985 | return; 986 | }/* update_attr() */ 987 | 988 | 989 | /************************************************************ 990 | * each_attribute_proces() * 991 | * * 992 | * Main function that processes object attributes one by one.* 993 | * Called from g_slist_foreach() function. * 994 | * First it tries to insert an attribute. * 995 | * If an error it assumes that attribute is already in * 996 | * a table and calls update_attr() to update it. * 997 | * Queries for the attributes are defined in Insert[] array. * 998 | * * 999 | * Returns: Nothing. Error code is stored in tr->error. * 1000 | * * 1001 | *************************************************************/ 1002 | static void each_attribute_process(void *element_data, void *tr_ptr) 1003 | { 1004 | int num; 1005 | const char *query_fmt; 1006 | int query_type; 1007 | int do_query; 1008 | Attribute_t *attr = element_data; 1009 | Transaction_t *tr = (Transaction_t *)tr_ptr; 1010 | unsigned int prefix, prefix_length, if_address; 1011 | unsigned int begin_in, end_in; 1012 | ip_v6word_t high, low; 1013 | 1014 | int begin_as, end_as; 1015 | char query[STR_XL]; 1016 | char * set_name; 1017 | char * rf_host; /* needs to be freed after use*/ 1018 | int rf_type, rf_port; 1019 | char *a_value; 1020 | int sq_info[3]; 1021 | char *mu_mntner; 1022 | int dummy_err; 1023 | char *sq_error; 1024 | ip_prefix_t dn_pref; 1025 | int sql_err; 1026 | int res; 1027 | char *token; 1028 | 1029 | /* we still want to continue to collect all possible errors*/ 1030 | /* if(tr->succeeded == 0) return; */ 1031 | 1032 | /* To switch off querying for some types of attributes */ 1033 | do_query=1; 1034 | 1035 | /* Determine the query type */ 1036 | query_type=DF_get_insert_query_type(attr->type); 1037 | 1038 | /* For loadind pass #1 we need to process only main tables */ 1039 | if(tr->load_pass==1){ 1040 | switch(query_type) { 1041 | case UD_MAIN_: 1042 | case UD_MA_U2: 1043 | case UD_MA_PR: 1044 | case UD_MA_RT: 1045 | case UD_MA_IN: 1046 | case UD_MA_I6: 1047 | case UD_MA_OR: 1048 | case UD_MA_AK: 1049 | break; 1050 | default: return; /* return for other than MAIN tables*/ 1051 | } 1052 | } 1053 | 1054 | query_fmt = DF_get_insert_query(attr->type); 1055 | 1056 | /* return if no query is defined for this attribute */ 1057 | if (strcmp(query_fmt, "") == 0) return; 1058 | 1059 | /* compose the query depending on the attribute */ 1060 | switch (query_type) { 1061 | case UD_MAIN_: /* for MAIN tables */ 1062 | if (ACT_UPDATE(tr->action)) do_query=0; 1063 | else 1064 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, attr->value); 1065 | break; 1066 | case UD_MA_OR: /* for the origin attribute */ 1067 | if (ACT_UPDATE(tr->action)) do_query=0; 1068 | else { 1069 | sprintf(query, query_fmt, tr->thread_ins, attr->value, tr->object_id); 1070 | tr->action |= TA_UPD_RX; 1071 | RP_pack_set_orig(attr->type, tr->packptr, attr->value); 1072 | } 1073 | break; 1074 | case UD_MA_PR: /* for person_role table*/ 1075 | if (ACT_UPDATE(tr->action)) do_query=0; 1076 | else 1077 | sprintf(query, query_fmt, tr->thread_ins, tr->class_type, tr->object_id, attr->value); 1078 | 1079 | /* check if we need to update NHR */ 1080 | if (ACT_UPD_NHR(tr->action)) { 1081 | /* Check if we can allocate it */ 1082 | res = NH_check(tr->nh, tr->sql_connection); 1083 | if(res == -1) { /* we cannot allocate this NIC handle (DB error) */ 1084 | tr->succeeded=0; 1085 | tr->error |= ERROR_U_DBS; 1086 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:cannot allocate nic-handle\n", ERROR_U_DBS, attr->type, attr->value); 1087 | ER_perror(FAC_UD, UD_SQL, "cannot allocate nic hdl[%s]\n", attr->value); 1088 | die; 1089 | } 1090 | else 1091 | if(res == 0) { /* we cannot allocate this NIC handle (full space or ID in use) */ 1092 | tr->succeeded=0; 1093 | tr->error |= ERROR_U_OBJ; 1094 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:nic-handle already in use\n", ERROR_U_OBJ, attr->type, attr->value); 1095 | return; 1096 | } 1097 | } 1098 | break; 1099 | case UD_MA_RT: /* for route table*/ 1100 | if (ACT_UPDATE(tr->action)) do_query=0; 1101 | else { 1102 | tr->action |= TA_UPD_RX; 1103 | RP_pack_set_pref4(attr->type, attr->value, tr->packptr, &prefix, &prefix_length); 1104 | /*ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s route: %u/%u\n", UD_TAG, prefix, prefix_length); */ 1105 | sprintf(query, query_fmt, tr->thread_ins, 1106 | tr->object_id, prefix, prefix_length); 1107 | } 1108 | break; 1109 | case UD_MA_IN: /* for inetnum table*/ 1110 | if (ACT_UPDATE(tr->action)) do_query=0; 1111 | else { 1112 | tr->action |= TA_UPD_RX; 1113 | RP_pack_set_rang(attr->type, attr->value, tr->packptr, &begin_in, &end_in); 1114 | /* XXX error handling ? */ 1115 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, begin_in, end_in); 1116 | } 1117 | break; 1118 | case UD_MA_I6: /* for inet6num table*/ 1119 | if (ACT_UPDATE(tr->action)) do_query=0; 1120 | else { 1121 | tr->action |= TA_UPD_RX; 1122 | RP_pack_set_pref6(attr->type, attr->value, tr->packptr, &high, &low, &prefix_length); 1123 | /* XXX error handling ? */ 1124 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, high, low, prefix_length); 1125 | } 1126 | break; 1127 | case UD_MA_U2: /* This is actually an update - go to update_attr - this is more natural */ 1128 | do_query=0; 1129 | break; 1130 | case UD_MA_AK: /* for as_block table*/ 1131 | if (ACT_UPDATE(tr->action)) do_query=0; 1132 | else { 1133 | convert_as_range(attr->value, &begin_as, &end_as); 1134 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, begin_as, end_as); 1135 | } 1136 | break; 1137 | case UD_AUX__: /* for AUX tables*/ 1138 | if((attr->type==A_AC) || (attr->type==A_TC) || (attr->type==A_ZC)) 1139 | if(strlen(attr->value)>MAX_NIC_HDL)*(attr->value + MAX_NIC_HDL)='\0'; 1140 | 1141 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value); 1142 | if(!IS_DUMMY_ALLOWED(tr->mode))strcat(query, " AND dummy=0 "); 1143 | break; 1144 | case UD_AX_MO: /* for member_of table*/ 1145 | set_name = get_set_name(tr->class_type); 1146 | /* ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s retrieved set name: %s\n", UD_TAG, set_name);*/ 1147 | sprintf(query, query_fmt, tr->thread_ins, 1148 | tr->object_id, set_name, tr->class_type, set_name, set_name, set_name, attr->value); 1149 | break; 1150 | case UD_AX_MR: /* for mbrs_by_ref table*/ 1151 | if ((g_strcasecmp(attr->value, "ANY")==0)) 1152 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, "ANY"); 1153 | else 1154 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value); 1155 | break; 1156 | case UD_AX_MU: /* for mnt_routes table*/ 1157 | a_value=g_strdup(attr->value); 1158 | token = a_value; 1159 | mu_mntner=strsep(&token, " \t"); 1160 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, mu_mntner); 1161 | free(a_value); 1162 | if (!IS_DUMMY_ALLOWED(tr->mode))strcat(query, " AND dummy=0 "); 1163 | break; 1164 | case UD_LEAF_: /* for LEAF tables*/ 1165 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, attr->value); 1166 | break; 1167 | case UD_LF_OT: /* for LEAF tables containing object_type field*/ 1168 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value); 1169 | break; 1170 | case UD_LF_AT: /* check PGPKEY. If yes - check the existence of key-cert.*/ 1171 | if(!IS_DUMMY_ALLOWED(tr->mode)){ 1172 | if(strncmp("PGPKEY", attr->value, 6)==0) { 1173 | if(get_ref_id(tr, "key_cert", "key_cert", attr->value, NULL)<=0) { 1174 | ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] no key-cert object[%s]", tr->transaction_id, attr->value); 1175 | tr->error|=ERROR_U_OBJ; 1176 | tr->succeeded=0; 1177 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:no key-cert object\n" ,ERROR_U_OBJ, attr->type, attr->value); 1178 | return; 1179 | } 1180 | } 1181 | } 1182 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value); 1183 | break; 1184 | case UD_LF_IF: /* for ifaddr tables*/ 1185 | /* Convert ascii ip -> numeric one*/ 1186 | convert_if(attr->value, &if_address); 1187 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, if_address); 1188 | break; 1189 | case UD_LF_RF: /* for refer table*/ 1190 | rf_host=convert_rf(attr->value, &rf_type, &rf_port); 1191 | if(rf_host == NULL) { 1192 | tr->error|=ERROR_U_OBJ; 1193 | tr->succeeded=0; 1194 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:incorrect attribute value\n" , 1195 | ERROR_U_OBJ, attr->type, attr->value); 1196 | return; 1197 | } 1198 | else { 1199 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, rf_type, rf_host, rf_port); 1200 | free(rf_host); 1201 | } 1202 | break; 1203 | case UD_LF_AY: /* for auth_override table*/ 1204 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, convert_time(attr->value)); 1205 | break; 1206 | default: 1207 | tr->succeeded=0; 1208 | tr->error |= ERROR_U_BUG; 1209 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:query not defined for the attribute\n" ,ERROR_U_BUG, attr->type, attr->value); 1210 | ER_perror(FAC_UD, UD_BUG, "query not defined for this type of attribute:[%d:%s]\n", attr->type, attr->value); 1211 | die; 1212 | break; 1213 | } 1214 | 1215 | /* Make the query. For primary keys go straight to updates if we are updating the object */ 1216 | if(do_query){ 1217 | ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query); 1218 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL); 1219 | } 1220 | else { 1221 | update_attr(attr, tr); 1222 | return; 1223 | } 1224 | 1225 | if (sql_err) { 1226 | /* we received an error */ 1227 | if(SQ_errno(tr->sql_connection) == ER_DUP_ENTRY){ /* Only error "Duplicate entry" may be considered*/ 1228 | if (ACT_UPDATE(tr->action)) { /* In update mode this is common (so actually not an error)*/ 1229 | update_attr(attr, tr); 1230 | return; 1231 | } 1232 | /* Otherwise this is a duplicate attribute, just ignore it */ 1233 | /* In the future if we are more stringent, checks may be added here */ 1234 | } 1235 | else { /* Other errors reveal a database/server problem*/ 1236 | sq_error=SQ_error(tr->sql_connection); 1237 | tr->error|=ERROR_U_DBS; 1238 | tr->succeeded=0; 1239 | ER_perror(FAC_UD, UD_BUG, "%s[%s]\n", sq_error, query); 1240 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,ERROR_U_DBS, attr->type, attr->value, sq_error); 1241 | die; 1242 | } 1243 | } /* if error occured */ 1244 | else { 1245 | /* If the query was successful */ 1246 | num = SQ_get_affected_rows(tr->sql_connection); 1247 | if(num>0){ /* this is OK*/ 1248 | /* Do some additional processing for member_of attribute */ 1249 | if ((attr->type == A_MO) && (!IS_DUMMY_ALLOWED(tr->mode))){ 1250 | /* ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s need to auth membership\n", UD_TAG);*/ 1251 | if(auth_member_of(attr, tr)!=0){ 1252 | tr->error|=ERROR_U_AUT; 1253 | tr->succeeded=0; 1254 | ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] membership not allowed [%d:%s]", tr->transaction_id, attr->type, attr->value); 1255 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:membership not allowed\n" ,ERROR_U_AUT, attr->type, attr->value); 1256 | } 1257 | } 1258 | else 1259 | /* Do some additional processing for reverse zones domains */ 1260 | if ((attr->type == A_DN) 1261 | && IP_revd_a2b(&dn_pref, attr->value)==IP_OK ) { 1262 | 1263 | if(insert_reverse_domain(tr, &dn_pref) != 0 ) { 1264 | tr->error|=ERROR_U_DBS; 1265 | tr->succeeded=0; 1266 | ER_perror(FAC_UD, UD_SQL, "cannot insert inverse domain:[%d:%s]\n", attr->type, attr->value); 1267 | die; 1268 | } 1269 | else { 1270 | /* save data for the radix tree update */ 1271 | tr->action |= TA_UPD_RX; 1272 | RP_pack_set_revd(attr->type, attr->value, tr->packptr); 1273 | } 1274 | } 1275 | return; 1276 | } 1277 | if(num == 0) { 1278 | /* this could be an empty update or a null select */ 1279 | SQ_get_info(tr->sql_connection, sq_info); 1280 | if (sq_info[SQL_DUPLICATES]>0) { 1281 | /* INSERT ... SELECT ... affected 0 rows, but there is 1 duplicate */ 1282 | /* which means that we already have such record in the table */ 1283 | /* this indicates that this is actually an update - update this attribute */ 1284 | if (sq_info[SQL_DUPLICATES]>1) { 1285 | tr->error|=ERROR_U_DBS; 1286 | tr->succeeded=0; 1287 | ER_perror(FAC_UD, UD_SQL, "too many duplicates:[%d:%s]\n", attr->type, attr->value); 1288 | die; 1289 | } 1290 | update_attr(attr, tr); 1291 | } 1292 | else { 1293 | /* this is an emty SELECT because there is no referred object */ 1294 | /* try to create dummy and repeat the original query*/ 1295 | 1296 | /* ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s no ref. integrity. Trying to create dummy\n", UD_TAG);*/ 1297 | 1298 | dummy_err = create_dummy(attr, tr); 1299 | if (dummy_err == 0) { 1300 | /* Dummy was created */ 1301 | g_string_sprintfa(tr->error_script,"W[%d][%d:%s]:dummy created\n" ,0, attr->type, attr->value); 1302 | ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query); 1303 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL); 1304 | num = SQ_get_affected_rows(tr->sql_connection); 1305 | if (sql_err) { 1306 | sq_error=SQ_error(tr->sql_connection); 1307 | ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", sq_error, query); 1308 | tr->error|=ERROR_U_DBS; 1309 | tr->succeeded=0; 1310 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" , 1311 | ERROR_U_DBS, attr->type, attr->value, sq_error); 1312 | die; 1313 | } 1314 | if (num==0) { 1315 | ER_perror(FAC_UD, UD_SQL, "0 rows affected [%s]\n", query); 1316 | tr->error|=ERROR_U_DBS; 1317 | tr->succeeded=0; 1318 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:re-insert qry\n" , 1319 | ERROR_U_DBS, attr->type, attr->value); 1320 | die; 1321 | } 1322 | } 1323 | else 1324 | if(dummy_err == 1) { 1325 | /* dummy not allowed */ 1326 | tr->error |= ERROR_U_OBJ; 1327 | tr->succeeded=0; 1328 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:dummy not allowed\n" ,ERROR_U_OBJ, attr->type, attr->value); 1329 | ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] dummy not allowed [%d:%s]", tr->transaction_id, attr->type, attr->value); 1330 | } 1331 | else { 1332 | /* SQL problem */ 1333 | tr->error|=ERROR_U_DBS; 1334 | tr->succeeded=0; 1335 | ER_perror(FAC_UD, UD_SQL, "dummy cannot be created [%d:%s]", attr->type, attr->value); 1336 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:dummy cannot be created\n" ,ERROR_U_DBS, attr->type, attr->value); 1337 | die; 1338 | } 1339 | } /* RI*/ 1340 | }/* if num == 0*/ 1341 | } /* if the query was successful */ 1342 | 1343 | return; 1344 | } /* each_attribute_process() */ 1345 | 1346 | 1347 | 1348 | /************************************************************ 1349 | * ud_each_primary_key_select() * 1350 | * * 1351 | * Function that forms a query for an object (w prinary keys)* 1352 | * Called from g_slist_foreach() function. * 1353 | * Primary keys are defined in Select[] array. * 1354 | * * 1355 | * Returns: Nothing. * 1356 | * * 1357 | *************************************************************/ 1358 | void ud_each_primary_key_select(void *element_data, void *result_ptr) 1359 | { 1360 | Attribute_t *attr = element_data; 1361 | Transaction_t *tr = (Transaction_t *)result_ptr; 1362 | const char *query_fmt; 1363 | unsigned int prefix, prefix_length; 1364 | unsigned int begin_in, end_in; 1365 | int begin_as, end_as; 1366 | ip_prefix_t prefstr; 1367 | ip_range_t rangstr; 1368 | ip_v6word_t i6_msb, i6_lsb; 1369 | 1370 | query_fmt = DF_get_select_query(attr->type); 1371 | /* if tr->query == NULL, then this is a pass to fill tr->K only (used in loader 1 pass) */ 1372 | 1373 | if (strcmp(query_fmt, "") != 0) { 1374 | switch (DF_get_select_query_type(attr->type)) { 1375 | case UD_MAIN_: 1376 | if(tr->query)g_string_sprintfa(tr->query, query_fmt, attr->value); 1377 | g_string_sprintfa(tr->K, attr->value); 1378 | break; 1379 | case UD_MA_RT: 1380 | IP_pref_a2v4(attr->value, &prefstr, &prefix, &prefix_length); 1381 | if(tr->query)g_string_sprintfa(tr->query, query_fmt, prefix, prefix_length); 1382 | g_string_sprintfa(tr->K, attr->value); 1383 | break; 1384 | case UD_MA_IN: 1385 | IP_rang_a2v4(attr->value, &rangstr, &begin_in, &end_in); 1386 | if(tr->query)g_string_sprintfa(tr->query, query_fmt, begin_in, end_in); 1387 | g_string_sprintfa(tr->K, attr->value); 1388 | break; 1389 | case UD_MA_I6: 1390 | IP_pref_a2v6(attr->value, &prefstr, &i6_msb, &i6_lsb, &prefix_length); 1391 | if(tr->query)g_string_sprintfa(tr->query, query_fmt, i6_msb, i6_lsb, prefix_length); 1392 | g_string_sprintfa(tr->K, attr->value); 1393 | break; 1394 | case UD_MA_AK: 1395 | convert_as_range(attr->value, &begin_as, &end_as); 1396 | if(tr->query)g_string_sprintfa(tr->query, query_fmt, begin_as, end_as); 1397 | g_string_sprintfa(tr->K, attr->value); 1398 | break; 1399 | default: 1400 | ER_perror(FAC_UD, UD_BUG, "query not defined for this type of attribute:[%d:%s]\n", attr->type, attr->value); 1401 | die; 1402 | 1403 | break; 1404 | } 1405 | } 1406 | } 1407 | 1408 | /************************************************************ 1409 | * perform_create(const Object_t *obj, Transaction_t *tr) * 1410 | * * 1411 | * Procedure for creating a new object. * 1412 | * First inserts object into 'last' table and gets object_id.* 1413 | * Then processes all attributes. * 1414 | * * 1415 | * Returns: tr->succeeded: >0 success, 0 - error * 1416 | * Error code is stored in tr->error. * 1417 | * * 1418 | *************************************************************/ 1419 | static int perform_create(Transaction_t *tr) 1420 | { 1421 | Object_t *obj; 1422 | char *str; 1423 | GString *query; 1424 | long timestamp; 1425 | int sql_err; 1426 | // long object_id; 1427 | 1428 | 1429 | if ((query = g_string_sized_new(STR_XL)) == NULL){ 1430 | tr->succeeded=0; 1431 | tr->error |= ERROR_U_MEM; 1432 | ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n"); 1433 | die; 1434 | } 1435 | 1436 | 1437 | obj=tr->object; 1438 | 1439 | str = (obj->object)->str; 1440 | timestamp=time(NULL); 1441 | tr->sequence_id=1; /* we start with 1*/ 1442 | /* Calculate the object_id - should be max+1 */ 1443 | /* XXX we cannot use autoincrement with MyISAM tables */ 1444 | /* XXX because they keep the max inserted id even if */ 1445 | /* XXX it was deleted later, thus causing gaps we don't want */ 1446 | 1447 | tr->object_id = SQ_get_max_id(tr->sql_connection, "object_id", "last") +1; 1448 | TR_update_id(tr); 1449 | 1450 | g_string_sprintf(query, "INSERT INTO last SET thread_id=%d, object_id=%ld, " 1451 | "timestamp=%ld, sequence_id=1, object_type=%d, object='%s', pkey='%s' ", 1452 | tr->thread_ins, tr->object_id, timestamp, tr->class_type, str, tr->K->str); 1453 | 1454 | ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query->str); 1455 | sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL); 1456 | 1457 | /* Check for affected rows. One row should be affected . */ 1458 | if (sql_err) { 1459 | tr->error|=ERROR_U_DBS; 1460 | tr->succeeded=0; 1461 | ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str); 1462 | die; 1463 | } 1464 | else { 1465 | g_slist_foreach(obj->attributes, each_attribute_process, tr); 1466 | } 1467 | g_string_free(query, TRUE); 1468 | return(tr->succeeded); 1469 | } /* perform_create() */ 1470 | 1471 | /************************************************************ 1472 | * perform_update(Transaction_t *tr) * 1473 | * * 1474 | * Procedure for updating (existing) object. * 1475 | * First processes all attributes. * 1476 | * Then saves previous object in 'history' and updates * 1477 | * 'last' table. * 1478 | * * 1479 | * Returns: tr->succeeded: >0 success, 0 - error * 1480 | * Error code is stored in tr->error. * 1481 | * * 1482 | *************************************************************/ 1483 | static int perform_update(Transaction_t *tr) 1484 | { 1485 | Object_t *obj; 1486 | char *str; 1487 | GString *query; 1488 | int num; 1489 | long sequence_id; 1490 | long timestamp; 1491 | char *sq_error; 1492 | int sql_err; 1493 | 1494 | 1495 | obj=tr->object; 1496 | /* get sequence number */ 1497 | 1498 | sequence_id = get_sequence_id(tr); 1499 | if(sequence_id==-1) { 1500 | tr->error|=ERROR_U_DBS; 1501 | tr->succeeded=0; 1502 | ER_perror(FAC_UD, UD_SQL, "cannot get sequence_id"); 1503 | die; 1504 | } 1505 | else tr->sequence_id=sequence_id; /* save it for rollback*/ 1506 | /* Update TR record */ 1507 | TR_update_id(tr); 1508 | 1509 | /* process each attribute one by one */ 1510 | g_slist_foreach(obj->attributes, each_attribute_process, tr); 1511 | 1512 | /* If we've already failed or this is fast load - just return */ 1513 | if((tr->succeeded == 0) || (tr->load_pass != 0)) return(tr->succeeded); 1514 | 1515 | /* No return: thread_id=0 */ 1516 | /* Do it only if previous transactions finished well */ 1517 | if ((query = g_string_sized_new(STR_XL)) == NULL){ 1518 | tr->succeeded=0; 1519 | tr->error |= ERROR_U_MEM; 1520 | ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring"); 1521 | die; 1522 | } 1523 | /* copy object to the history table */ 1524 | g_string_sprintf(query,"INSERT history " 1525 | "SELECT %d, object_id, sequence_id, timestamp, object_type, object, pkey, serial, prev_serial " 1526 | "FROM last " 1527 | "WHERE object_id=%ld ", tr->thread_ins, tr->object_id); 1528 | 1529 | ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query->str); 1530 | sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL); 1531 | 1532 | /* Check for affected rows. One row should be affected . */ 1533 | num = SQ_get_affected_rows(tr->sql_connection); 1534 | if (num < 1) { 1535 | tr->error|=ERROR_U_DBS; 1536 | tr->succeeded=0; 1537 | if (sql_err) { 1538 | sq_error=SQ_error(tr->sql_connection); 1539 | ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str); 1540 | die; 1541 | } 1542 | else { 1543 | ER_perror(FAC_UD, UD_SQL, "0 rows affected [%s]\n", query->str); 1544 | /* This is to check that this is really could happen */ 1545 | die; 1546 | } 1547 | g_string_free(query, TRUE); 1548 | return(tr->succeeded); 1549 | } 1550 | 1551 | /* Insert new version into the last */ 1552 | 1553 | /* Put a timestamp */ 1554 | str = (obj->object)->str; 1555 | timestamp=time(NULL); 1556 | 1557 | /* update last for commit/rollback */ 1558 | 1559 | g_string_sprintf(query, "INSERT last " 1560 | "SET thread_id=%d, object_id=%ld, sequence_id=%ld, timestamp=%ld, object_type=%d, object='%s', pkey='%s' ", 1561 | tr->thread_ins, tr->object_id, tr->sequence_id+1, timestamp, tr->class_type, str, tr->K->str); 1562 | 1563 | 1564 | ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query->str); 1565 | sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL); 1566 | 1567 | /* Check for affected rows. One row should be affected */ 1568 | num = SQ_get_affected_rows(tr->sql_connection); 1569 | if (num < 1) { 1570 | tr->error|=ERROR_U_DBS; 1571 | tr->succeeded=0; 1572 | if(sql_err) { 1573 | g_string_sprintfa(tr->error_script,"E[%d][:]:UPDATE last failed:%s\n" ,ERROR_U_DBS,SQ_error(tr->sql_connection)); 1574 | ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str); 1575 | die; 1576 | } 1577 | else { 1578 | ER_perror(FAC_UD, UD_SQL, "0 rows affected [%s]\n", query->str); 1579 | /* This is to check that this is really could happen */ 1580 | die; 1581 | } 1582 | g_string_free(query, TRUE); 1583 | return(tr->succeeded); 1584 | } 1585 | g_string_free(query, TRUE); 1586 | return(tr->succeeded); 1587 | } /* perform_update() */ 1588 | 1589 | 1590 | 1591 | 1592 | /************************************************************ 1593 | * int object_process(Transaction_t *tr) * 1594 | * * 1595 | * This is the interface between core and upper layer * 1596 | * All it gets is Transaction *tr, which contains all * 1597 | * necessary information, including the object in its * 1598 | * internal representation. * 1599 | * * 1600 | * Returns: tr->succeeded: >0 success, 0 - error * 1601 | * Error code is stored in tr->error. * 1602 | * * 1603 | *************************************************************/ 1604 | int object_process(Transaction_t *tr) 1605 | { 1606 | int res; 1607 | char *nic; 1608 | int commit_now; 1609 | 1610 | /* for fast loader we do not perform commits/rollbacks */ 1611 | if(tr->load_pass == 0) commit_now = 0; else commit_now = 1; 1612 | 1613 | /* create and initialize TR record for crash recovery */ 1614 | TR_create_record(tr); 1615 | 1616 | if(ACT_DELETE(tr->action)){ 1617 | ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s object: delete", UD_TAG); 1618 | /* check referential integrity of deletion */ 1619 | UD_check_ref(tr); 1620 | /* for person & role - free the nic-handle in the NHR */ 1621 | if(ACT_UPD_NHR(tr->action) && tr->succeeded && ((tr->class_type==C_PN) || (tr->class_type==C_RO)) && tr->nh ){ 1622 | res = NH_free(tr->nh, tr->sql_connection, commit_now); 1623 | 1624 | if(res == -1) { 1625 | tr->succeeded=0; 1626 | tr->error |= ERROR_U_DBS; 1627 | ER_perror(FAC_UD, UD_SQL, "cannot delete nic handle"); 1628 | die; 1629 | } 1630 | else if(res == 0) { 1631 | tr->succeeded=0; 1632 | tr->error |= ERROR_U_OBJ; 1633 | ER_perror(FAC_UD, UD_SQL, "nic handle not found"); 1634 | die; 1635 | } 1636 | } 1637 | /* if everything is Ok we are ready to commit */ 1638 | if (tr->succeeded){ 1639 | /* update object_id and sequence_id fields */ 1640 | tr->sequence_id = get_sequence_id(tr); 1641 | TR_update_id(tr); 1642 | 1643 | /* checkpoint the TR - we are going to commit*/ 1644 | CP_COMMIT(tr->action); TR_update_escript(tr); TR_update_status(tr); 1645 | 1646 | /* send an ack */ 1647 | UD_ack(tr); 1648 | 1649 | /* delete the object and checkpoint it*/ 1650 | UD_delete(tr); 1651 | UD_update_rx(tr, RX_OPER_DEL); 1652 | 1653 | /* we need to update sequence_id because it was changed during update */ 1654 | CP_DELETE_PASSED(tr->action); TR_update_id(tr); TR_update_status(tr); 1655 | 1656 | /* Commit nic-handle deletion to the repository */ 1657 | NH_commit(tr->sql_connection); 1658 | 1659 | CP_COMMIT_NH_PASSED(tr->action); TR_update_status(tr); 1660 | 1661 | } 1662 | else { /* just send an ack */ 1663 | UD_ack(tr); 1664 | } 1665 | return(tr->succeeded); /*commit is not needed*/ 1666 | } 1667 | else if(ACT_UPDATE(tr->action)){ 1668 | ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s object: update\n", UD_TAG); 1669 | perform_update(tr); 1670 | 1671 | /* Commit nic-handle allocation (if any) to the repository if we are replacing dummy*/ 1672 | if(ACT_UPD_NHR(tr->action) && tr->succeeded && ((tr->class_type==C_PN) || (tr->class_type==C_RO)) && tr->nh ){ 1673 | /* convert nh to DB nIC handle before registration */ 1674 | /* because there nh will bee freed */ 1675 | nic = NH_convert(tr->nh); 1676 | 1677 | if(nic==NULL)res=-1; else res = NH_register(tr->nh, tr->sql_connection, commit_now); 1678 | 1679 | if(res == -1) { 1680 | tr->succeeded=0; 1681 | tr->error |= ERROR_U_DBS; 1682 | ER_perror(FAC_UD, UD_SQL, "cannot allocate nic handle\n"); 1683 | die; 1684 | } 1685 | else if(res == 0) { 1686 | tr->succeeded=0; 1687 | tr->error |= ERROR_U_OBJ; 1688 | ER_perror(FAC_UD, UD_SQL, "nic handle already in use\n"); 1689 | die; 1690 | } 1691 | else { /* copy the NH to the report to return to DBupdate */ 1692 | /* Convert nh to the database format */ 1693 | g_string_sprintfa(tr->error_script,"I[%d][%s]\n", A_NH, nic); 1694 | UT_free(nic); 1695 | } 1696 | } 1697 | } 1698 | else if(ACT_CREATE(tr->action)){ 1699 | ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s object: create", UD_TAG); 1700 | perform_create(tr); 1701 | 1702 | /* Commit nic-handle allocation (if any) to the repository */ 1703 | if(ACT_UPD_NHR(tr->action) && tr->succeeded && ((tr->class_type==C_PN) || (tr->class_type==C_RO)) && tr->nh ){ 1704 | /* convert nh to DB nIC handle before registration */ 1705 | nic = NH_convert(tr->nh); 1706 | 1707 | if(nic==NULL)res=-1; else res = NH_register(tr->nh, tr->sql_connection, commit_now); 1708 | 1709 | if(res == -1) { 1710 | tr->succeeded=0; 1711 | tr->error |= ERROR_U_DBS; 1712 | ER_perror(FAC_UD, UD_SQL, "cannot allocate nic handle"); 1713 | die; 1714 | } 1715 | else if(res == 0) { 1716 | tr->succeeded=0; 1717 | tr->error |= ERROR_U_OBJ; 1718 | ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] object: nic handle %s already in use", tr->transaction_id, nic); 1719 | g_string_sprintfa(tr->error_script,"E[%d][nic handle %s already in use]\n", A_NH, nic); 1720 | } 1721 | else { /* copy the NH to the report to return to DBupdate */ 1722 | g_string_sprintfa(tr->error_script,"I[%d][%s]\n", A_NH, nic); 1723 | UT_free(nic); 1724 | } 1725 | } 1726 | 1727 | } 1728 | else { 1729 | ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] object: unknown action", tr->transaction_id); 1730 | tr->succeeded=0; 1731 | tr->error|=ERROR_U_BADOP; 1732 | return(tr->succeeded); 1733 | } 1734 | 1735 | if(tr->load_pass == 0) { /* not for fast loader*/ 1736 | /* update object_id and sequence_id fields */ 1737 | TR_update_id(tr); 1738 | 1739 | if (tr->succeeded) { 1740 | /*ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s Commit transaction\n", UD_TAG); */ 1741 | /* checkpoint the TR - we are going to commit*/ 1742 | CP_COMMIT(tr->action); TR_update_escript(tr); TR_update_status(tr); 1743 | 1744 | /* send an ack */ 1745 | UD_ack(tr); 1746 | /* commit the transaction and checkpoint it */ 1747 | 1748 | UD_commit(tr); 1749 | /* Commit nic-handle modifications to the repository */ 1750 | 1751 | NH_commit(tr->sql_connection); 1752 | 1753 | CP_COMMIT_NH_PASSED(tr->action); TR_update_status(tr); 1754 | /* TR will be marked as clean in UD_create_serial() */ 1755 | } 1756 | else { 1757 | /*ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s roll back transaction\n", UD_TAG); */ 1758 | /* send an ack */ 1759 | UD_ack(tr); 1760 | UD_rollback(tr); 1761 | 1762 | CP_ROLLBACK_PASSED(tr->action); TR_update_status(tr); 1763 | 1764 | /* rollback nic-handle modifications to the repository */ 1765 | NH_rollback(tr->sql_connection); 1766 | 1767 | 1768 | CP_ROLLBACK_NH_PASSED(tr->action); TR_update_status(tr); 1769 | /* Delete TR record if in update mode. Next time (if any) DBupdate tries to submit, we'll start from scratch */ 1770 | /* In NRTM mode we create serial anyway, so the record will be deleted */ 1771 | /* after serial is created TR record will be deleted in */ 1772 | 1773 | } 1774 | } 1775 | return(tr->succeeded); 1776 | } /* object_process() */ 1777 |