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