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