1 | /*************************************** 2 | $Revision: 1.5 $ 3 | 4 | Core functions for update lower layer 5 | 6 | Status: NOT REVUED, NOT TESTED 7 | 8 | Author(s): Chris Ottrey, Andrei Robachevsky 9 | 10 | ******************/ /****************** 11 | Modification History: 12 | andrei (17/01/2000) Created. 13 | ******************/ /****************** 14 | Copyright (c) 2000 RIPE NCC 15 | 16 | All Rights Reserved 17 | 18 | Permission to use, copy, modify, and distribute this software and its 19 | documentation for any purpose and without fee is hereby granted, 20 | provided that the above copyright notice appear in all copies and that 21 | both that copyright notice and this permission notice appear in 22 | supporting documentation, and that the name of the author not be 23 | used in advertising or publicity pertaining to distribution of the 24 | software without specific, written prior permission. 25 | 26 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 27 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL 28 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY 29 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 30 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 31 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 32 | ***************************************/ 33 | #include "ud.h" 34 | #include "ud_int.h" 35 | #include "UD_queries.def" 36 | 37 | char * const Type2main[] = { 38 | "as_block", 39 | "as_set", 40 | "aut_num", 41 | "domain", 42 | "inet_rtr", 43 | "inet6num", 44 | "inetnum", 45 | "key_cert", 46 | "limerick", 47 | "mntner", 48 | "person_role", //pn 49 | "person_role", //ro 50 | "route", 51 | "route_set", 52 | NULL 53 | }; /* Main tables names for object types */ 54 | 55 | 56 | static int perform_update(Transaction_t *tr); 57 | 58 | static int perform_create(Transaction_t *tr); 59 | 60 | static void each_primary_key_select(void *element_data, void *result_ptr); 61 | 62 | static void each_attribute_process(void *element_data, void *tr_ptr); 63 | 64 | static int update_attr(Attribute_t *attr, Transaction_t *tr); 65 | 66 | static int create_dummy(Attribute_t *attr, Transaction_t *tr); 67 | 68 | static int auth_member_of(Attribute_t *attr, Transaction_t *tr); 69 | 70 | 71 | 72 | 73 | 74 | /*************************************************** 75 | * char *s_split(char *line) * 76 | * * 77 | * Consequently returns words of the 'line' * 78 | * When there are no words it returns NULL * 79 | * You need to retreive all words ! * 80 | * * 81 | * NB This function damages 'line' replacing * 82 | * whitespace with '\0' * 83 | * *************************************************/ 84 | static char *s_split(char *line) 85 | { 86 | static char *delim; 87 | static char *token=NULL; 88 | 89 | if(token==NULL)token=line; 90 | else token=delim; 91 | 92 | if(token==NULL)return(token); 93 | while(isspace((int)*token))token++; 94 | delim=token; 95 | 96 | while(!isspace((int)*delim)) { 97 | if((*delim)=='\0'){ 98 | if(delim==token)token=NULL; 99 | delim=NULL; return(token); 100 | } 101 | delim++; 102 | } 103 | *delim='\0'; delim++; 104 | return(token); 105 | 106 | } 107 | 108 | /* The same as s_split() but returns nwords words */ 109 | /* and the rest of the line */ 110 | static char *s_splitn(char *line, int nwords) 111 | { 112 | static char *delim; 113 | static char *token=NULL; 114 | static int w=0; 115 | 116 | 117 | if(token==NULL)token=line; 118 | else token=delim; 119 | 120 | w++; if(w>nwords){ w=0; delim=token; token=NULL; return(delim); } 121 | 122 | if(token==NULL)return(token); 123 | while(isspace((int)*token))token++; 124 | delim=token; 125 | 126 | while(!isspace((int)*delim)) { 127 | if((*delim)=='\0'){ 128 | if(delim==token)token=NULL; 129 | delim=NULL; return(token); 130 | } 131 | delim++; 132 | } 133 | *delim='\0'; delim++; 134 | return(token); 135 | 136 | 137 | } 138 | 139 | /********************************************************** 140 | * Attribute expansion/conversion functions * 141 | ***********************************************************/ 142 | 143 | /* Convert route attribute into numbers */ 144 | er_ret_t expand_rt(char *avalue, unsigned int *prefix, unsigned int *prefix_length) 145 | { 146 | ip_prefix_t pref; 147 | er_ret_t ret; 148 | 149 | ret = IP_pref_e2b(&pref, avalue); 150 | *prefix = pref.ip.words[0]; 151 | *prefix_length=pref.bits; 152 | return(ret); 153 | } 154 | 155 | /* Convert ifaddr attribute into numbers */ 156 | er_ret_t convert_if(char *avalue, unsigned int *address) 157 | { 158 | char *delim; 159 | ip_addr_t ipaddr; 160 | er_ret_t ret; 161 | 162 | if ((delim=index(avalue, ' '))!=NULL) *delim='\0'; 163 | ret = IP_addr_e2b(&ipaddr, avalue); 164 | *address = ipaddr.words[0]; 165 | return(ret); 166 | } 167 | 168 | /* Convert inetnum attribute into numbers */ 169 | er_ret_t convert_in(char *rangstr, unsigned int *begin_in, unsigned int *end_in) 170 | { 171 | ip_range_t myrang; 172 | er_ret_t ret; 173 | 174 | if( IP_rang_e2b(&myrang, rangstr) != IP_OK ) { 175 | // see if's a valid IP, maybe it's an IPv4 classful range 176 | if( IP_addr_e2b( &myrang.begin, rangstr ) == IP_OK ) 177 | if ((ret=IP_rang_classful( &myrang , &myrang.begin )) != IP_OK ) return (ret); 178 | } 179 | *begin_in=myrang.begin.words[0]; 180 | *end_in=myrang.end.words[0]; 181 | return(IP_OK); 182 | } 183 | 184 | /* Convert refer attribute. Free host after use ! */ 185 | char *convert_rf(char *avalue, int *type, int *port) 186 | { 187 | char *delim, *token; 188 | char buff[STR_M]; 189 | char *host; 190 | 191 | host=NULL; 192 | strcpy(buff, avalue); 193 | g_strchug(buff); 194 | delim=index(buff, ' '); 195 | *delim='\0'; 196 | delim++; 197 | 198 | // convert the type 199 | if(strcmp(buff, S_RIPE)==0)*type=RF_RIPE; 200 | else if(strcmp(buff, S_INTERNIC)==0)*type=RF_INTERNIC; 201 | else if(strcmp(buff, S_SIMPLE)==0)*type=RF_SIMPLE; 202 | 203 | token=delim; 204 | g_strchug(token); 205 | delim=index(token, ' '); 206 | if(delim){ 207 | *delim='\0'; 208 | delim++; 209 | } 210 | // convert the hostname 211 | host = g_strdup(token); 212 | 213 | // convert port number 214 | if(delim){ 215 | token=delim; 216 | *port = atoi(token); 217 | if (*port==0) *port=RF_DEF_PORT; // default port number 218 | } else *port=RF_DEF_PORT; 219 | return(host); 220 | } 221 | 222 | 223 | /* Convert AS# into integer */ 224 | static int convert_as(char *as) 225 | { 226 | char *ptr; 227 | ptr=as; ptr++; ptr++; 228 | return(atoi(ptr)); 229 | } 230 | 231 | /* Convert AS range (AS4321 - AS5672) into numbers */ 232 | int convert_as_range(const char *as_range, int *begin, int *end) 233 | { 234 | char buf[STR_M]; 235 | strcpy(buf, as_range); //save it 236 | *begin=convert_as(s_split(buf)); 237 | s_split(buf); // should be '-' 238 | *end=convert_as(s_split(buf)); 239 | while(s_split(buf)); 240 | return(0); 241 | } 242 | 243 | /* Convert time in ASCII format (19991224) into time_t unix time */ 244 | time_t convert_time(char *asc_time) 245 | { 246 | struct tm tm; 247 | char buf[STR_S]; 248 | char *ptr; 249 | 250 | 251 | bzero(&tm, sizeof(tm)); 252 | 253 | strncpy(buf, asc_time, 4); ptr=buf+4; *ptr='\0'; 254 | tm.tm_year = atoi(buf) - 1900; 255 | 256 | strncpy(buf, (asc_time+4), 2); ptr=buf+2; *ptr='\0'; 257 | tm.tm_mon = atoi(buf) - 1; 258 | 259 | strncpy(buf, (asc_time+6), 2); ptr=buf+2; *ptr='\0'; 260 | tm.tm_mday = atoi(buf); 261 | 262 | return(mktime(&tm)); 263 | 264 | } 265 | 266 | /********************************* 267 | * M I S C ***********************/ 268 | 269 | /************************************************************ 270 | * long get_object_id() * 271 | * Queries the database for an object. * 272 | * For constructing a query uses each__primary_key_select() * 273 | * * 274 | * Returns: * 275 | * >0 - object exists, returns object_id * 276 | * 0 - object does not exist * 277 | * -1 - DB error (f.e. more than one object with the same PK) * 278 | * * 279 | * **********************************************************/ 280 | long get_object_id(Transaction_t *tr) 281 | { 282 | Object_t *obj=tr->object; 283 | SQ_result_set_t *sql_result; 284 | SQ_row_t *sql_row; 285 | char *sql_str; 286 | GString *query; 287 | long object_id=0; 288 | 289 | if ((query = g_string_sized_new(STR_XL)) == NULL){ 290 | fprintf(stderr, "E: cannot allocate gstring\n"); 291 | tr->succeeded=0; 292 | tr->error |= ERROR_U_MEM; 293 | return(ERROR_U_MEM); 294 | } 295 | 296 | g_string_sprintf(query, "SELECT * FROM %s WHERE",Type2main[obj->type]); 297 | g_slist_foreach(obj->attributes, each_primary_key_select, query); 298 | /* truncate the last ' AND '*/ 299 | g_string_truncate(query, (query->len) - 4); 300 | 301 | /* execute query */ 302 | sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query->str); 303 | g_string_free(query, TRUE); 304 | 305 | if(sql_result == NULL) { 306 | fprintf(stderr,"ERROR: %s\n", SQ_error(tr->sql_connection)); 307 | return(-1); 308 | } 309 | 310 | if ((sql_row = SQ_row_next(sql_result)) != NULL) { 311 | /* Object exists */ 312 | sql_str = SQ_get_column_string(sql_result, sql_row, OBJECT_ID); 313 | if (sql_str != NULL) { 314 | object_id = atol(sql_str); 315 | free(sql_str); 316 | } 317 | 318 | /* We must process all the rows of the result */ 319 | /* otherwise we'll have them as part of the next qry */ 320 | while ( (sql_row = SQ_row_next(sql_result)) != NULL) object_id=-1; 321 | } else 322 | object_id=0; // object does not exist 323 | 324 | if(sql_result)SQ_free_result(sql_result); 325 | return(object_id); 326 | } 327 | 328 | /************************************************************ 329 | * get_field_str() * 330 | * * 331 | * Returns string containing the field. * 332 | * field - field name to be retrieved * 333 | * ref_tbl_name - name of the table containing the field * 334 | * ref_name - reference name * 335 | * attr_value - reference value * 336 | * condition - additional condition ( f.e. 'AND dummy=0' * 337 | * * 338 | * Returns: * 339 | * String containing the field. Needs to be freed after use * 340 | * NULL in case of an error * 341 | * * 342 | *************************************************************/ 343 | char *get_field_str(Transaction_t *tr, char *field, 344 | char *ref_tbl_name, char *ref_name, 345 | char * attr_value, char *condition) 346 | { 347 | static char query[STR_L]; 348 | SQ_result_set_t *sql_result; 349 | SQ_row_t *sql_row; 350 | char *sql_str; 351 | 352 | sprintf(query, "SELECT %s FROM %s " 353 | "WHERE %s='%s' ", 354 | field, ref_tbl_name, ref_name, attr_value); 355 | if (condition)strcat(query, condition); 356 | 357 | //fprintf(stderr, "D:<get_field_str>:query: %s\n", query); 358 | sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query); 359 | 360 | if(sql_result == NULL) { 361 | fprintf(stderr,"ERROR: %s\n", SQ_error(tr->sql_connection)); 362 | return(NULL); 363 | } 364 | 365 | 366 | if ((sql_row = SQ_row_next(sql_result)) != NULL) { 367 | sql_str = SQ_get_column_string(sql_result, sql_row, 0); 368 | 369 | /* We must process all the rows of the result,*/ 370 | /* otherwise we'll have them as part of the next qry */ 371 | while ( (sql_row = SQ_row_next(sql_result)) != NULL) { 372 | fprintf(stderr, "E:<get_field_str> error : Dupl PK[%s]\n", query); 373 | if(sql_str)free(sql_str); sql_str=NULL; 374 | } 375 | } 376 | else sql_str=NULL; 377 | 378 | if(sql_result){ SQ_free_result(sql_result); sql_result=NULL; } 379 | return(sql_str); 380 | } 381 | 382 | /************************************************************ 383 | * long get_sequence_id(Transaction_t *tr) 384 | * >0 - success 385 | * -1 - sql error 386 | * 387 | * **********************************************************/ 388 | 389 | long get_sequence_id(Transaction_t *tr) 390 | { 391 | char *sql_str; 392 | char str_id[STR_M]; 393 | long sequence_id=-1; 394 | 395 | 396 | sprintf(str_id, "%ld", tr->object_id); 397 | sql_str= get_field_str(tr, "sequence_id", "last", "object_id", str_id, NULL); 398 | if(sql_str) { 399 | sequence_id = atol(sql_str); 400 | // fprintf(stderr, "D: Retrieved set serial id = %ld\n", sequence_id); 401 | free(sql_str); 402 | } 403 | 404 | return(sequence_id); 405 | 406 | } 407 | 408 | 409 | /************************************************************ 410 | * long get_ref_id(char *ref_tbl_name, char *ref_name, char * attr_value) 411 | * >0 - success 412 | * -1 - sql error 413 | * 414 | * **********************************************************/ 415 | 416 | static long get_ref_id(Transaction_t *tr, char *ref_tbl_name, char *ref_name, char * attr_value, char *condition) 417 | { 418 | char *sql_str; 419 | long ref_id=-1; 420 | 421 | //fprintf(stderr, "D:<get_ref_id>: entering...\n"); 422 | 423 | sql_str= get_field_str(tr, "object_id", ref_tbl_name, ref_name, attr_value, condition); 424 | if(sql_str) { 425 | ref_id = atol(sql_str); 426 | // fprintf(stderr, "D: Retrieved set serial id = %ld\n", ref_id); 427 | free(sql_str); 428 | } 429 | return(ref_id); 430 | } 431 | 432 | 433 | static int isnichandle(char *name) 434 | { 435 | return(MA_isset(WK_new(name), WK_NIC_HDL)); 436 | } 437 | 438 | static int sql_info(SQ_connection_t *sql_connection, int info[3]) 439 | { 440 | int ii; 441 | char *colon, *buf_ptr, buf[20]; 442 | char *infoline; 443 | 444 | //fprintf(stderr, "D: Getting additional information about query\n"); 445 | infoline=mysql_info(sql_connection); 446 | //fprintf(stderr, "D: %s\n", infoline); 447 | ii=0; 448 | colon = infoline; 449 | while (*colon != '\0') { 450 | colon++; 451 | buf_ptr=buf; 452 | if(isdigit((int)*colon)){ 453 | while(isdigit((int)*colon)){ 454 | *buf_ptr=*colon; buf_ptr++; colon++; 455 | } 456 | *buf_ptr='\0'; 457 | info[ii]=atoi(buf); ii++; 458 | } 459 | } 460 | // free(infoline); 461 | //fprintf(stderr, "D: return %d\n", res[res_type]); 462 | return(0); 463 | } 464 | 465 | 466 | static char *get_set_name(C_Type_t class_type) 467 | { 468 | switch(class_type){ 469 | case C_RT: return("route_set"); 470 | case C_AN: return("as_set"); 471 | default: return(NULL); 472 | } 473 | } 474 | 475 | 476 | /************************************************************ 477 | * auth_member_of() * 478 | * * 479 | * Function that checks the authorization for membership * 480 | * (i.e. if the object is authorized to be a memeber by * 481 | * mbrs-by-ref attribute of the set is refers by member-of * 482 | * attribute). * 483 | * First checks if 'mbrs-by-ref: ANY' * 484 | * If not then checks that maintner referenced by * 485 | * mbrs-by-ref attribute of the set is the one in mnt-by. * 486 | * * 487 | * Returns: * 488 | * 0 success * 489 | * 1 not allowed * 490 | * -1 SQL error * 491 | * * 492 | *************************************************************/ 493 | static int auth_member_of(Attribute_t *attr, Transaction_t *tr) 494 | { 495 | GString *query; 496 | SQ_result_set_t *sql_result; 497 | SQ_row_t *sql_row; 498 | //char *sql_str; 499 | char *set_name; 500 | //long set_id; 501 | //my_ulonglong num; 502 | int error; 503 | 504 | 505 | error=0; 506 | 507 | /* Check if set has mbrs_by_ref==ANY 508 | In such case mbrs_by_ref.mnt_id==0 509 | */ 510 | 511 | if ((query = g_string_sized_new(STR_XL)) == NULL){ 512 | tr->succeeded=0; 513 | tr->error |= ERROR_U_MEM; 514 | fprintf(stderr, "E: cannot allocate gstring\n"); 515 | return(-1); 516 | } 517 | 518 | set_name= get_set_name(tr->class_type); 519 | // fprintf(stderr, "D:<auth_member_of>: Got set name: %s\n", set_name); 520 | g_string_sprintf(query,"SELECT %s.object_id FROM mbrs_by_ref, %s " 521 | "WHERE mbrs_by_ref.object_id=%s.object_id " 522 | "AND %s.%s='%s' AND mbrs_by_ref.mnt_id=0 ", 523 | set_name, set_name, set_name, set_name, set_name, attr->value); 524 | // fprintf(stderr, "D:<auth_member_of>: query: %s\n", query->str); 525 | 526 | sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query->str); 527 | // if (sql_result ==NULL) { // ???????? 528 | // fprintf(stderr, "E:<auth_member_of>: NULL SQL result[%s]\n", query->str); 529 | // g_string_free(query, TRUE); 530 | // return(1); 531 | // } 532 | 533 | if ((sql_result==NULL) || ((sql_row = SQ_row_next(sql_result))==NULL)){ 534 | if(sql_result){ SQ_free_result(sql_result); sql_result=NULL; } 535 | 536 | /* Check if our mnt_by belongs to mbrs_by_ref list of the set */ 537 | g_string_sprintf(query, "SELECT mbrs_by_ref.object_id FROM route_set, mbrs_by_ref, mnt_by " 538 | "WHERE mbrs_by_ref.mnt_id=mnt_by.mnt_id " 539 | "AND mnt_by.object_id=%ld " 540 | "AND %s.object_id=mbrs_by_ref.object_id " 541 | "AND %s.%s='%s' " 542 | "AND mnt_by.thread_id!=0 ", 543 | tr->object_id, set_name, set_name, set_name, attr->value); 544 | 545 | // fprintf(stderr, "D:<auth_member_of>: query: %s\n", query->str); 546 | 547 | sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query->str); 548 | 549 | if(sql_result == NULL) { 550 | fprintf(stderr,"ERROR: %s\n", SQ_error(tr->sql_connection)); 551 | g_string_free(query, TRUE); 552 | return(-1); 553 | } 554 | 555 | if ((sql_row = SQ_row_next(sql_result)) == NULL) { 556 | /* Membership is not authorized */ 557 | fprintf(stderr, "E:<auth_member_of> : Membership is not autorized[%s]\n", query->str); 558 | if(sql_result){ SQ_free_result(sql_result); sql_result=NULL; } 559 | g_string_free(query, TRUE); 560 | return(1); 561 | } 562 | } 563 | 564 | // sql_str = SQ_get_column_string(sql_result, sql_row, 0); 565 | /* We must process all the rows of the result, otherwise we'll have them as part of the next qry */ 566 | while ( (sql_row = SQ_row_next(sql_result)) != NULL) { 567 | fprintf(stderr, "E:<auth_member_of> error : More than one object with the same PK\n"); 568 | error=-1; 569 | } 570 | if(sql_result){ SQ_free_result(sql_result); sql_result=NULL; } 571 | g_string_free(query, TRUE); 572 | return(0); 573 | }/* auth_member_of() */ 574 | 575 | 576 | /************************************************************ 577 | * create_dummy() * 578 | * * 579 | * Function that creates a dummy object (that is one that * 580 | * is referenced from an object but does not * 581 | * exist in the database). * 582 | * Dummy object exists only in relevant main and 'last' * 583 | * tables. Its creation is controlled by tr->dummy_allowed. * 584 | * Queries for the dummies are defined in Dummy[] array. * 585 | * * 586 | * Returns: * 587 | * 0 success * 588 | * 1 no rf integrity and dummy not allowed 589 | * -1 SQL error * 590 | * * 591 | *************************************************************/ 592 | static int create_dummy(Attribute_t *attr, Transaction_t *tr) 593 | { 594 | SQ_result_set_t *sql_result; 595 | char *query_fmt; 596 | int num; 597 | long dummy_id; 598 | char query[STR_L]; 599 | //int result; 600 | char *set_name; 601 | char *p_name; 602 | int query_type; 603 | long timestamp; 604 | char str_id[STR_M]; 605 | gchar *chopped_nh=NULL; 606 | gchar *attr_value=NULL; 607 | 608 | 609 | query_fmt = Dummy[attr->type].qry; 610 | if (strcmp(query_fmt, "") == 0) { fprintf(stderr, "E:<create_dummy>: empty query string\n"); return(1); } 611 | if ((attr->type!=A_MO) && (tr->dummy != 1)) return(1); 612 | 613 | /* insert dummy in the last table */ 614 | sprintf(str_id, "%ld", tr->object_id); 615 | timestamp=time(NULL); 616 | sprintf(query, "INSERT INTO last SET thread_id=%d, timestamp=%ld, object_type=%d, object='DUMMY for %s'", 617 | tr->thread_ins, timestamp, DUMMY_TYPE, str_id); 618 | // fprintf(stderr, "D: making dummy entry in the last table\n %s\n", query); 619 | sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query); 620 | num = mysql_affected_rows(tr->sql_connection); 621 | // fprintf(stderr, "D: query: %d rows affected\n", num); 622 | if (sql_result)SQ_free_result(sql_result); 623 | if ((num == -1) || (num == 0)) { 624 | //fprintf(stderr, "E: dummy->last:[%s]\n", query); 625 | return(-1); 626 | } 627 | 628 | /* insert dummy in the main table */ 629 | dummy_id=mysql_insert_id(tr->sql_connection); 630 | tr->dummy_id[tr->ndummy]=dummy_id; 631 | tr->ndummy++; // increase number of attempts to create dummy 632 | // fprintf(stderr, "D:<create_dummy>:dummy_id=%ld\n", dummy_id); 633 | query_type=Dummy[attr->type].qtype; 634 | switch (query_type) { 635 | case UD_AX_PR: 636 | // chop nic-hdl if bigger that MAX_NIC_HDL 637 | if(strlen(attr->value)>MAX_NIC_HDL){ 638 | chopped_nh = g_strndup(attr->value, MAX_NIC_HDL); 639 | attr_value=chopped_nh; 640 | } else attr_value = attr->value; 641 | sprintf(query, query_fmt, tr->thread_ins, dummy_id, attr_value, DUMMY_TYPE); 642 | if(chopped_nh){ free(chopped_nh); chopped_nh=NULL;} 643 | break; 644 | case UD_AX_MT: 645 | sprintf(query, query_fmt, tr->thread_ins, dummy_id, attr->value, DUMMY_TYPE); 646 | break; 647 | // as-set, route-set 648 | case UD_AX_MO: 649 | set_name = get_set_name(tr->class_type); 650 | sprintf(query, query_fmt, set_name, tr->thread_ins, dummy_id, set_name, attr->value); 651 | break; 652 | default: 653 | fprintf(stderr, "E: query not defined for this type of attribute[%d]\n", attr->type); 654 | break; 655 | } 656 | 657 | //fprintf(stderr, "D: query: %s\n", query); 658 | sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query); 659 | num = mysql_affected_rows(tr->sql_connection); 660 | // fprintf(stderr, "D: query: %d rows affected\n", num); 661 | if (sql_result)SQ_free_result(sql_result); 662 | if ((num == -1) || (num == 0)) { 663 | fprintf(stderr, "E: dummy->main:[num=%d][%s]\n", num, query); 664 | return(-1); 665 | } 666 | 667 | if( query_type == UD_AX_MO ){ // Create row in mbrs_by_ref 668 | sprintf(query, " INSERT mbrs_by_ref SET thread_id=%d, object_id=%ld, mnt_id=0, object_type=%d ", 669 | tr->thread_ins,dummy_id, DUMMY_TYPE); 670 | // fprintf(stderr, "D: query: %s\n", query); 671 | sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query); 672 | num = mysql_affected_rows(tr->sql_connection); 673 | // fprintf(stderr, "D: query: %d rows affected\n", num); 674 | if (sql_result)SQ_free_result(sql_result); 675 | if ((num == -1) || (num == 0)) { 676 | fprintf(stderr, "E: dummy->main:[num=%d][%s]\n", num, query); 677 | return(-1); 678 | } 679 | } 680 | else 681 | if( (query_type == UD_AX_PR) && (!isnichandle (attr->value)) ){ // Create rows in names 682 | // parse the names 683 | // fprintf(stderr,"adding names for dummy\n"); 684 | query_fmt = Insert[A_PN].qry; 685 | attr_value = g_strdup(attr->value); 686 | while((p_name=s_split(attr_value))){ 687 | sprintf(query, query_fmt, tr->thread_ins, dummy_id, DUMMY_TYPE, p_name); 688 | // fprintf(stderr, "D: query: %s\n", query); 689 | sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query); 690 | num = mysql_affected_rows(tr->sql_connection); 691 | // fprintf(stderr, "D: query: %d rows affected\n", num); 692 | if (sql_result)SQ_free_result(sql_result); 693 | } 694 | free(attr_value); 695 | } 696 | 697 | return(0); 698 | } 699 | 700 | /************************************************************ 701 | * update_attr() * 702 | * * 703 | * Function that updates an attribute if it already exists. * 704 | * Called from each_attribute_proces() function if it * 705 | * cannot insert the row. * 706 | * Queries for the attributes are defined in Update[] array. * 707 | * * 708 | * Returns: Nothing. Error code is stored in tr->succeeded. * 709 | * * 710 | *************************************************************/ 711 | static int update_attr(Attribute_t *attr, Transaction_t *tr) 712 | { 713 | SQ_result_set_t * sql_result; 714 | int num; 715 | char *query_fmt; 716 | //GString *query; 717 | char *set_name; 718 | unsigned int if_address; 719 | char * rf_host; 720 | int rf_port, rf_type; 721 | gchar *chopped_nh=NULL; 722 | char *a_value; 723 | //int dupl; 724 | int sq_info[3]; 725 | char * condition; 726 | char query[STR_L]; 727 | 728 | if(tr->load_pass!=0) return(0); 729 | 730 | // fprintf(stderr, "D: updating attribute...\n"); 731 | 732 | query_fmt = Update[attr->type].qry; 733 | if (strcmp(query_fmt, "") == 0) return(0); 734 | 735 | switch (Update[attr->type].qtype) { 736 | case UD_MAIN_: sprintf(query, query_fmt, tr->thread_upd, tr->object_id); 737 | break; 738 | case UD_MA_PR: 739 | sprintf(query, query_fmt, tr->thread_upd, tr->class_type, tr->object_id); 740 | break; 741 | case UD_MA_LA: // save the new value for commit 742 | //g_string_free(query, TRUE); 743 | tr->save=attr->value; 744 | return(0); 745 | break; 746 | case UD_AX_PR: 747 | a_value = attr->value; 748 | if(strlen(attr->value)>MAX_NIC_HDL){ // This is for non-conformant admin-c, etc. 749 | chopped_nh = g_strndup(attr->value, MAX_NIC_HDL); 750 | a_value=chopped_nh; 751 | } 752 | if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL; 753 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 754 | get_ref_id(tr, "person_role", "nic_hdl", a_value, condition)); 755 | if(chopped_nh) free(chopped_nh); 756 | break; 757 | case UD_AX_MT: 758 | if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL; 759 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 760 | get_ref_id(tr, "mntner", "mntner", attr->value, condition)); 761 | break; 762 | case UD_AX_MO: 763 | set_name = get_set_name(tr->class_type); 764 | // fprintf(stderr, "D: retrieved set name: %s\n", set_name); 765 | if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL; 766 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 767 | get_ref_id(tr, set_name, set_name, attr->value, condition)); 768 | break; 769 | case UD_AX_MR: 770 | if ((strcmp(attr->value, "ANY")==0) || (strcmp(attr->value, "any")==0) || (strcmp(attr->value, "Any")==0)) 771 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 772 | get_ref_id(tr, "mntner", "mntner", "ANY",NULL)); 773 | else { 774 | if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL; 775 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 776 | get_ref_id(tr, "mntner", "mntner", attr->value, condition)); 777 | } 778 | break; 779 | case UD_LEAF_: 780 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, attr->value); 781 | break; 782 | case UD_LF_IF: 783 | // Convert ascii ip -> numeric one. Later to save in tr->save while processing INSERT 784 | convert_if(attr->value, &if_address); 785 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, if_address); 786 | break; 787 | case UD_LF_RF: 788 | rf_host=convert_rf(attr->value, &rf_type, &rf_port); 789 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, rf_type, rf_host, rf_port); 790 | if(rf_host)free(rf_host); 791 | break; 792 | case UD_LF_AY: 793 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, convert_time(attr->value)); 794 | break; 795 | default: 796 | fprintf(stderr, "E:<e_a_u> query not defined for this type of attribute:[%d]\n", attr->type); 797 | tr->error|=ERROR_U_BUG; 798 | tr->succeeded=0; 799 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:no update qry\n" ,ERROR_U_BUG, attr->type, attr->value); 800 | break; 801 | } 802 | //fprintf(stderr, "D: update: [%s]", query); 803 | 804 | sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query); 805 | num = mysql_affected_rows(tr->sql_connection); 806 | // fprintf(stderr, "D: query: %d rows affected\n", num); 807 | if ((num == -1)) { 808 | fprintf(stderr, "E:<each_attribute_create> update query:[%d][%s]\n", num, query); 809 | tr->error|=ERROR_U_DBS; 810 | tr->succeeded=0; 811 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:update qry\n" ,ERROR_U_DBS, attr->type, attr->value); 812 | } 813 | else 814 | if(num == 0) { // check for duplicates 815 | sql_info(tr->sql_connection, sq_info); // REPLACE ... SELECT 816 | if ((sq_info[SQL_DUPLICATES]==0) && (sq_info[SQL_MATCHES]==0)) { // this is because of dummies 817 | fprintf(stderr, "E: Update: empty query result: [%s]\n", query); 818 | tr->error|=ERROR_U_DBS; 819 | tr->succeeded=0; 820 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:null update qry res\n" ,ERROR_U_DBS, attr->type, attr->value); 821 | } // else duplicate entry - silently drop it 822 | } 823 | if (sql_result){ SQ_free_result(sql_result);sql_result=NULL; } 824 | if (attr->type == A_MO){ 825 | // fprintf(stderr, "D:<e_a_p>: need to auth membership\n"); 826 | if(auth_member_of(attr, tr)!=0){ 827 | tr->error|=ERROR_U_AUT; 828 | tr->succeeded=0; 829 | fprintf(stderr, "E:<each_attribute_create>: membership not allowed\n"); 830 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:membership not allowed\n" ,ERROR_U_AUT, attr->type, attr->value); 831 | } 832 | } 833 | //fprintf(stderr, "D:<update_attr>: returning \n"); 834 | return(0); 835 | }/* update_attr() */ 836 | 837 | 838 | /************************************************************ 839 | * each_attribute_proces() * 840 | * * 841 | * Main function that processes object attributes one by one.* 842 | * Called from g_slist_foreach() function. * 843 | * First it tries to insert an attribute. * 844 | * If an error it assumes that attribute is already in * 845 | * a table and calls update_attr() to update it. * 846 | * Queries for the attributes are defined in Insert[] array. * 847 | * * 848 | * Returns: Nothing. Error code is stored in tr->succeeded. * 849 | * * 850 | *************************************************************/ 851 | static void each_attribute_process(void *element_data, void *tr_ptr) 852 | { 853 | SQ_result_set_t * sql_result; 854 | //my_ulonglong num; 855 | int num; 856 | char *query_fmt; 857 | int query_type; 858 | //int dupl; 859 | int do_query; 860 | Attribute_t *attr = element_data; 861 | Transaction_t *tr = (Transaction_t *)tr_ptr; 862 | unsigned int prefix, prefix_length; 863 | unsigned int begin_in, end_in; 864 | int begin_as, end_as; 865 | //GString *query_u; 866 | char query[STR_L]; 867 | char * set_name; 868 | char * rf_host; // needs to be deleted after use 869 | int rf_type, rf_port; 870 | gchar *chopped_nh=NULL; 871 | char *a_value; 872 | int sq_info[3]; 873 | char *mu_mntner, *mu_prefix; 874 | int dummy_err; 875 | 876 | static rx_bin_data_t rx_bin_data; 877 | static rx_inum_data_t rx_inum_data; 878 | 879 | 880 | if(tr->succeeded == 0) return; // no sense to continue 881 | 882 | do_query=1; 883 | 884 | query_type=Insert[attr->type].qtype; 885 | 886 | /* For loadind pass #1 we need to process only main tables */ 887 | if(tr->load_pass==1){ 888 | switch(query_type) { 889 | case UD_MAIN_: 890 | case UD_MA_U2: 891 | case UD_MA_PR: 892 | case UD_MA_RT: 893 | case UD_MA_IN: 894 | case UD_MA_I6: 895 | case UD_MA_LA: 896 | case UD_MA_AK: 897 | break; 898 | default: return; // return for other than MAIN tables 899 | } 900 | } 901 | 902 | query_fmt = Insert[attr->type].qry; 903 | 904 | if (strcmp(query_fmt, "") == 0) return; 905 | // fprintf(stderr,"[%d]:[%s]\n", attr->type, attr->value); 906 | query_type=Insert[attr->type].qtype; 907 | switch (query_type) { 908 | case UD_MAIN_: 909 | if (tr->action==TR_UPDATE) do_query=0; 910 | else 911 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, attr->value); 912 | break; 913 | case UD_MA_U2: 914 | if (tr->action==TR_UPDATE) do_query=0; 915 | else 916 | sprintf(query, query_fmt, tr->thread_ins, attr->value, tr->object_id); 917 | if(attr->type == A_OR) { 918 | save_rx_orig(&rx_bin_data, attr->value); 919 | tr->save = (void *)&rx_bin_data; // just in case 920 | } 921 | break; 922 | case UD_MA_PR: 923 | if (tr->action==TR_UPDATE) do_query=0; 924 | else 925 | sprintf(query, query_fmt, tr->thread_ins, tr->class_type, tr->object_id, attr->value); 926 | break; 927 | case UD_MA_RT: 928 | if (tr->action==TR_UPDATE) do_query=0; 929 | else { 930 | expand_rt(attr->value, &prefix, &prefix_length); 931 | //fprintf(stderr, "D: route: %u/%u\n", prefix, prefix_length); 932 | sprintf(query, query_fmt, tr->thread_ins, 933 | tr->object_id, prefix, prefix_length); 934 | // save stuff for radix update 935 | save_rx_pref(&rx_bin_data, prefix, prefix_length); 936 | tr->save = (void *)&rx_bin_data; 937 | } 938 | break; 939 | case UD_MA_IN: 940 | if (tr->action==TR_UPDATE) do_query=0; 941 | else { 942 | convert_in(attr->value, &begin_in, &end_in); 943 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, begin_in, end_in); 944 | save_rx_rang(&rx_inum_data, begin_in, end_in); 945 | tr->save = (void *)&rx_inum_data; 946 | } 947 | break; 948 | case UD_MA_I6: 949 | break; 950 | case UD_MA_LA: // save the new value for commit 951 | tr->save=attr->value; 952 | // fprintf(stderr, "D:<e_a_p> attribute saved: %s\n", tr->save); 953 | return; 954 | break; 955 | case UD_MA_AK: 956 | if (tr->action==TR_UPDATE) do_query=0; 957 | else { 958 | convert_as_range(attr->value, &begin_as, &end_as); 959 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, begin_as, end_as); 960 | } 961 | break; 962 | case UD_AUX__: 963 | a_value = attr->value; 964 | if((attr->type==A_AC) || (attr->type==A_TC) || (attr->type==A_ZC)) 965 | if(strlen(attr->value)>MAX_NIC_HDL){ 966 | chopped_nh = g_strndup(attr->value, MAX_NIC_HDL); 967 | a_value=chopped_nh; 968 | } 969 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, a_value); 970 | if(tr->dummy!=1)strcat(query, " AND dummy=0 "); 971 | if(chopped_nh){ free(chopped_nh); chopped_nh=NULL;} 972 | break; 973 | case UD_AX_MO: 974 | set_name = get_set_name(tr->class_type); 975 | // fprintf(stderr, "D: retrieved set name: %s\n", set_name); 976 | sprintf(query, query_fmt, tr->thread_ins, 977 | tr->object_id, set_name, tr->class_type, set_name, set_name, set_name, attr->value); 978 | break; 979 | case UD_AX_MR: 980 | if ((strcmp(attr->value, "ANY")==0) || (strcmp(attr->value, "any")==0) || (strcmp(attr->value, "Any")==0)) 981 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, "ANY"); 982 | else 983 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value); 984 | break; 985 | case UD_AX_MU: 986 | a_value=g_strdup(attr->value); 987 | mu_mntner=s_splitn(a_value, 1); 988 | mu_prefix=s_splitn(a_value, 1); 989 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, mu_prefix, tr->class_type, mu_mntner); 990 | free(a_value); 991 | if(tr->dummy!=1)strcat(query, " AND dummy=0 "); 992 | break; 993 | case UD_LEAF_: 994 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, attr->value); 995 | break; 996 | case UD_LF_OT: 997 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value); 998 | break; 999 | case UD_LF_AT: // check PGPKEY. If yes - check the existence of key-cert. 1000 | if(tr->dummy!=1){ 1001 | if(strncmp("PGPKEY", attr->value, 6)==0) { 1002 | if(get_ref_id(tr, "key_cert", "key_cert", attr->value, NULL)<=0) { 1003 | fprintf(stderr, "E:<e_a_p>: No key-cert object.\n"); 1004 | tr->error|=ERROR_U_OBJ; 1005 | tr->succeeded=0; 1006 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:no key-cert object\n" ,ERROR_U_OBJ, attr->type, attr->value); 1007 | return; 1008 | } 1009 | } 1010 | } 1011 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value); 1012 | break; 1013 | case UD_LF_IF: 1014 | // Convert ascii ip -> numeric one 1015 | convert_if(attr->value, &prefix); 1016 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, prefix); 1017 | break; 1018 | case UD_LF_RF: 1019 | rf_host=convert_rf(attr->value, &rf_type, &rf_port); 1020 | sprintf(query, query_fmt, tr->thread_ins, 0 /*tr->object_id*/ , rf_type, rf_host, rf_port); 1021 | if(rf_host)free(rf_host); 1022 | break; 1023 | case UD_LF_AY: 1024 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, convert_time(attr->value)); 1025 | break; 1026 | default: 1027 | fprintf(stderr, "E: query not defined for this type of attribute\n"); 1028 | break; 1029 | } 1030 | 1031 | //fprintf(stderr, "D: insert: [%s]", query); 1032 | 1033 | if(do_query){ 1034 | sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query); 1035 | num = mysql_affected_rows(tr->sql_connection); 1036 | if (sql_result)SQ_free_result(sql_result);sql_result=NULL; 1037 | } 1038 | else { 1039 | update_attr(attr, tr); 1040 | return; 1041 | } 1042 | 1043 | // fprintf(stderr, "D: query: %d rows affected\n", num); 1044 | 1045 | if(num>0){ // this is OK 1046 | // if attr=="member_of" we need additional processing 1047 | if (attr->type == A_MO){ 1048 | // fprintf(stderr, "D:<e_a_p>: need to auth membership\n"); 1049 | if(auth_member_of(attr, tr)!=0){ 1050 | tr->error|=ERROR_U_AUT; 1051 | tr->succeeded=0; 1052 | fprintf(stderr, "E:<each_attribute_create>: membership not allowed\n"); 1053 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:membership not allowed\n" ,ERROR_U_AUT, attr->type, attr->value); 1054 | } 1055 | } 1056 | return; 1057 | } 1058 | 1059 | if(num == -1){ // if not update that is the error condition. free resources and return (except some attributes) 1060 | if (tr->action==TR_UPDATE) { 1061 | update_attr(attr, tr); 1062 | return; 1063 | } 1064 | else { 1065 | switch(attr->type) { 1066 | case A_EM: break; // duplicate e-mail: 1067 | case A_PN: break; // fe: Antony Antony 1068 | case A_RO: break; // fe: IB og Co Reklame og Marketing 1069 | 1070 | default: 1071 | // !!!!!!!! tr->succeeded=0; fprintf(stderr, "E: query returned an error: [%s]\n", query->str); 1072 | break; 1073 | } 1074 | } 1075 | } 1076 | else 1077 | if(num == 0) { 1078 | sql_info(tr->sql_connection, sq_info); 1079 | if (sq_info[SQL_DUPLICATES]>0) { // update attribute 1080 | if (sq_info[SQL_DUPLICATES]>1) { // this is an error - more that 1 duplicate 1081 | fprintf(stderr, "E: Update: Too many duplicates for query: [%s]\n", query); 1082 | tr->error|=ERROR_U_DBS; 1083 | tr->succeeded=0; 1084 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:duplicates\n" ,ERROR_U_DBS, attr->type, attr->value); 1085 | return; 1086 | } 1087 | update_attr(attr, tr); 1088 | } 1089 | else { // try to create dummy and repeat query 1090 | 1091 | // fprintf(stderr, "W: no ref. integrity. Trying to create dummy..."); 1092 | 1093 | dummy_err = create_dummy(attr, tr); 1094 | if (dummy_err == 0) { 1095 | // fprintf(stderr, "D: ... dummy OK\n"); 1096 | g_string_sprintfa(tr->error_script,"W[%d][%d:%s]:dummy created\n" ,0, attr->type, attr->value); 1097 | // fprintf(stderr, "D: repeating query: %s\n", query); 1098 | sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query); 1099 | num = mysql_affected_rows(tr->sql_connection); 1100 | if (sql_result) { SQ_free_result(sql_result); sql_result=NULL;} 1101 | if ((num == -1) || (num==0)) { 1102 | tr->error|=ERROR_U_DBS; 1103 | tr->succeeded=0; 1104 | fprintf(stderr, "E:<each_attribute_create>: insert query: [%s]\n", query); 1105 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:insert qry\n" ,ERROR_U_DBS, attr->type, attr->value); 1106 | } 1107 | } 1108 | else 1109 | if(dummy_err == 1) { 1110 | tr->error |= ERROR_U_OBJ; 1111 | tr->succeeded=0; 1112 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:rf failure\n" ,ERROR_U_OBJ, attr->type, attr->value); 1113 | } 1114 | else { 1115 | tr->error|=ERROR_U_DBS; 1116 | tr->succeeded=0; 1117 | fprintf(stderr, "E:<each_attribute_create>: dummy not created\n"); 1118 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:dummy not created\n" ,ERROR_U_DBS, attr->type, attr->value); 1119 | } 1120 | }// RI 1121 | }// if num == 0 1122 | return; 1123 | } /* each_attribute_process() */ 1124 | 1125 | 1126 | 1127 | /************************************************************ 1128 | * each_primary_key_select() * 1129 | * * 1130 | * Function that forms a query for an object (w prinary keys)* 1131 | * Called from g_slist_foreach() function. * 1132 | * Primary keys are defined in Select[] array. * 1133 | * * 1134 | * Returns: Nothing. Error code is stored in tr->succeeded. * 1135 | * * 1136 | *************************************************************/ 1137 | static void each_primary_key_select(void *element_data, void *result_ptr) 1138 | { 1139 | Attribute_t *attr = element_data; 1140 | GString *result = (GString *)result_ptr; 1141 | char *query_fmt; 1142 | unsigned int prefix, prefix_length; 1143 | unsigned int begin_in, end_in; 1144 | int begin_as, end_as; 1145 | 1146 | query_fmt = Select[attr->type].qry; 1147 | 1148 | // fprintf(stderr, "D: qry fmt: %s\n", query_fmt); 1149 | 1150 | if (strcmp(query_fmt, "") != 0) { 1151 | switch (Select[attr->type].qtype) { 1152 | case UD_MAIN_: 1153 | g_string_sprintfa(result, query_fmt, attr->value); 1154 | break; 1155 | case UD_MA_RT: 1156 | expand_rt(attr->value, &prefix, &prefix_length); 1157 | g_string_sprintfa(result, query_fmt, prefix, prefix_length); 1158 | break; 1159 | case UD_MA_IN: 1160 | convert_in(attr->value, &begin_in, &end_in); 1161 | g_string_sprintfa(result, query_fmt, begin_in, end_in); 1162 | break; 1163 | case UD_MA_AK: 1164 | convert_as_range(attr->value, &begin_as, &end_as); 1165 | g_string_sprintfa(result, query_fmt, begin_as, end_as); 1166 | break; 1167 | default: 1168 | fprintf(stderr, "E:<e_p_k_s>: query not defined for this type of attribute:[%d]\n", attr->type); 1169 | 1170 | 1171 | break; 1172 | } 1173 | //fprintf(stderr, "D: each_primary_key_select(): %s\n",result->str); 1174 | } 1175 | } 1176 | 1177 | /************************************************************ 1178 | * perform_create(const Object_t *obj, Transaction_t *tr) * 1179 | * * 1180 | * Procedure for creating a new object. * 1181 | * First inserts object into 'last' table and gets object_id.* 1182 | * Then processes all attributes. * 1183 | * * 1184 | * Returns: Nothing. Error code is stored in tr->succeeded. * 1185 | * * 1186 | *************************************************************/ 1187 | static int perform_create(Transaction_t *tr) 1188 | { 1189 | Object_t *obj=tr->object; 1190 | SQ_result_set_t *sql_result; 1191 | char *str; 1192 | static char query[STR_XXXL]; 1193 | int num; 1194 | long timestamp; 1195 | 1196 | str = (obj->object)->str; 1197 | timestamp=time(NULL); 1198 | sprintf(query, "INSERT INTO last SET thread_id=%d, timestamp=%ld, object_type=%d, object='%s' ", 1199 | tr->thread_ins, timestamp, tr->class_type, str); 1200 | 1201 | sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query); 1202 | num = mysql_affected_rows(tr->sql_connection); 1203 | if (sql_result)SQ_free_result(sql_result); 1204 | if ((num == -1) || (num == 0)) { 1205 | fprintf(stderr, "E ERROR!<perform_create>: INSERT last failed:%d\n", num); 1206 | tr->error|=ERROR_U_DBS; 1207 | tr->succeeded=0; 1208 | g_string_sprintfa(tr->error_script,"E[%d][:]:INSERT last failed\n" ,ERROR_U_DBS); 1209 | } 1210 | else { 1211 | tr->object_id=mysql_insert_id(tr->sql_connection); 1212 | g_slist_foreach(obj->attributes, each_attribute_process, tr); 1213 | } 1214 | return(0); 1215 | } /* perform_create() */ 1216 | 1217 | /************************************************************ 1218 | * perform_update(Transaction_t *tr) * 1219 | * * 1220 | * Procedure for updating (existing) object. * 1221 | * First processes all attributes. * 1222 | * Then saves previous object in 'history' and updates * 1223 | * 'last' table. * 1224 | * * 1225 | * Returns: Nothing. Error code is stored in tr->succeeded. * 1226 | * * 1227 | *************************************************************/ 1228 | static int perform_update(Transaction_t *tr) 1229 | { 1230 | Object_t *obj=tr->object; 1231 | SQ_result_set_t * sql_result; 1232 | char *str; 1233 | char str_id[STR_M]; 1234 | char *sql_str; 1235 | static char query[STR_XXXL]; 1236 | int num; 1237 | long sequence_id; 1238 | long timestamp; 1239 | 1240 | /* process each attribute one by one */ 1241 | g_slist_foreach(obj->attributes, each_attribute_process, tr); 1242 | 1243 | /* If we've already failed or this is fast load - just return */ 1244 | if((tr->succeeded == 0) || (tr->load_pass != 0)) return(0); 1245 | 1246 | /* No return: thread_id=0 */ 1247 | /* Do it only if previous transactions finished well */ 1248 | 1249 | /* copy object to the history table */ 1250 | fprintf(stderr, "INSERT history\n"); 1251 | sprintf(query,"INSERT history " 1252 | "SELECT 0, object_id, sequence_id, timestamp, object_type, object " 1253 | "FROM last " 1254 | "WHERE object_id=%ld ", tr->object_id); 1255 | 1256 | sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query); 1257 | num = mysql_affected_rows(tr->sql_connection); 1258 | if (sql_result)SQ_free_result(sql_result); 1259 | if ((num == -1) || (num == 0)) { 1260 | fprintf(stderr, "E ERROR!<perform_update>: INSERT history failed:[%d][%s]\n", num, query); 1261 | tr->error|=ERROR_U_DBS; 1262 | tr->succeeded=0; 1263 | g_string_sprintfa(tr->error_script,"E[%d][:]:INSERT history failed\n" ,ERROR_U_DBS); 1264 | return(-1); 1265 | } 1266 | 1267 | /* get sequence number */ 1268 | //fprintf(stderr, "get seq\n"); 1269 | sprintf(str_id, "%ld", tr->object_id); 1270 | sql_str= get_field_str(tr, "sequence_id", "last", "object_id", str_id, NULL); 1271 | if(sql_str) { 1272 | sequence_id = atol(sql_str); 1273 | free(sql_str); 1274 | } 1275 | else { 1276 | fprintf(stderr, "E ERROR!<perform_update> cannot get sequence_id: %d\n", num); 1277 | tr->error|=ERROR_U_DBS; 1278 | tr->succeeded=0; 1279 | g_string_sprintfa(tr->error_script,"E[%d][:]:cannot get seq ID\n" ,ERROR_U_DBS); 1280 | return(-1); 1281 | } 1282 | 1283 | tr->sequence_id=sequence_id; // save it for rollback 1284 | 1285 | 1286 | /* insert new version into the last */ 1287 | str = (obj->object)->str; 1288 | timestamp=time(NULL); 1289 | sequence_id++; 1290 | 1291 | //fprintf(stderr, "UPDATE last\n"); 1292 | /* If we are here - it's almost commit. Otherwise this row will not be updated at all. */ 1293 | sprintf(query, "UPDATE last " 1294 | "SET thread_id=0, sequence_id=%ld, timestamp=%ld, object_type=%d, object='%s' " 1295 | "WHERE object_id=%ld ", 1296 | sequence_id, timestamp, tr->class_type, str, tr->object_id); 1297 | 1298 | sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query); 1299 | num = mysql_affected_rows(tr->sql_connection); 1300 | if (sql_result)SQ_free_result(sql_result); 1301 | if ((num == -1) || (num == 0)) { 1302 | fprintf(stderr, "E ERROR!<perform_update>: INSERT last failed: [%d][%s]\n", num, query); 1303 | tr->error|=ERROR_U_DBS; 1304 | tr->succeeded=0; 1305 | g_string_sprintfa(tr->error_script,"E[%d][:]:INSERT last failed\n" ,ERROR_U_DBS); 1306 | return(-1); 1307 | } 1308 | return(0); 1309 | } /* perform_update() */ 1310 | 1311 | 1312 | 1313 | 1314 | /************************************************************ 1315 | * int object_process(Transaction_t *tr) * 1316 | * * 1317 | * This is the interface between core and upper layer * 1318 | * All it gets is Transaction *tr, which contains all * 1319 | * necessary information, including the object in its * 1320 | * internal representation. * 1321 | * * 1322 | * Returns: Nothing. Error code is stored in tr->succeeded. * 1323 | * * 1324 | *************************************************************/ 1325 | int object_process(Transaction_t *tr) 1326 | { 1327 | 1328 | /* not supported */ 1329 | if(tr->class_type==C_I6) { 1330 | tr->succeeded=0; tr->error |= ERROR_U_NSUP; 1331 | fprintf(stderr, "Object type currently not supported\n"); 1332 | return(-1); 1333 | } 1334 | 1335 | switch(tr->action){ 1336 | case TR_DELETE: 1337 | fprintf(stderr, "D: Action: Delete..."); 1338 | printf("\tD: Action: Delete..."); 1339 | delete(tr); 1340 | return(0); //commit is not needed 1341 | break; 1342 | 1343 | case TR_UPDATE: 1344 | fprintf(stderr, "D: Action: Update..."); 1345 | printf("\tD: Action: Update..."); 1346 | perform_update(tr); 1347 | break; 1348 | 1349 | case TR_CREATE: 1350 | fprintf(stderr, "D: Action: Create..."); 1351 | printf("\tD: Action: Create..."); 1352 | perform_create(tr); 1353 | break; 1354 | 1355 | default: 1356 | fprintf(stderr, "D: Action: Unknown..."); 1357 | tr->succeeded=0; 1358 | tr->error|=ERROR_U_BADOP; 1359 | return(-1); 1360 | break; 1361 | } 1362 | if(tr->load_pass == 0) { // not for fast loader 1363 | if (tr->succeeded == 1) { 1364 | //fprintf(stderr, "D: Commit transaction...\n"); 1365 | commit(tr); 1366 | return(0); 1367 | } 1368 | else { 1369 | //fprintf(stderr, "D: Roll back transaction...\n"); 1370 | rollback(tr); 1371 | return(0); 1372 | } 1373 | } 1374 | return(0); 1375 | } /* object_process() */ 1376 |