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