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