Esempio n. 1
0
/* q should be set when joining */
static int binding_row_compare(fs_query *q, fs_binding *b1, fs_binding *b2, int p1, int p2, int length1, int length2)
{
    if (p1 >= length1 && p2 >= length2) {
        return 0;
    }
    if (p1 >= length1) {
#ifdef DEBUG_COMPARE
        printf("CMP from past end\n");
#endif
	return 1;
    } else if (p2 >= length2) {
#ifdef DEBUG_COMPARE
        printf("CMP to past end\n");
#endif
	return -1;
    }

    for (int i=1; b1[i].name; i++) {
        if (!b1[i].sort) continue;

        const fs_rid b1v = table_value(b1, i, p1);
        const fs_rid b2v = table_value(b2, i, p2);

        if (b1v == FS_RID_NULL) {
            if (b2v == FS_RID_NULL) {
                /* both bindings are null, assume equality */
                continue;
            }

            /* b1v is null, b2v is not, assume null < b2v  */
            return -2;
        }

        if (b2v == FS_RID_NULL) {
            /* b2v is null, b1v is not, assume b1v > null */
            return 2;
        }

        if (b1v > b2v) {
#ifdef DEBUG_COMPARE
            printf("CMP %llx > %llx\n", b1v, b2v);
#endif
            return 1;
        }
        if (b1v < b2v) {
#ifdef DEBUG_COMPARE
            printf("CMP %llx < %llx\n", b1v, b2v);
#endif
            return -1;
        }
    }

    return 0;
}
Esempio n. 2
0
/*
 * Return code:
 *	0  - End Of Table
 * 	-1 - Error
 *	-2 - Last change changed - again
 *	+1 - ok, continue
 */
static int
table_check_response(struct tabwork *work, const struct snmp_pdu *resp)
{
	const struct snmp_value *b;
	struct entry *e;

	if (resp->error_status != SNMP_ERR_NOERROR) {
		if (snmp_client.version == SNMP_V1 &&
		    resp->error_status == SNMP_ERR_NOSUCHNAME &&
		    resp->error_index ==
		    (work->descr->last_change.len == 0) ? 1 : 2)
			/* EOT */
			return (0);
		/* Error */
		seterr(&snmp_client, "error fetching table: status=%d index=%d",
		    resp->error_status, resp->error_index);
		return (-1);
	}

	for (b = resp->bindings; b < resp->bindings + resp->nbindings; b++) {
		if (work->descr->last_change.len != 0 && b == resp->bindings) {
			if (!asn_is_suboid(&work->descr->last_change, &b->var) ||
			    b->var.len != work->descr->last_change.len + 1 ||
			    b->var.subs[work->descr->last_change.len] != 0) {
				seterr(&snmp_client,
				    "last_change: bad response");
				return (-1);
			}
			if (b->syntax != SNMP_SYNTAX_TIMETICKS) {
				seterr(&snmp_client,
				    "last_change: bad syntax %u", b->syntax);
				return (-1);
			}
			if (work->first) {
				work->last_change = b->v.uint32;
				work->first = 0;

			} else if (work->last_change != b->v.uint32) {
				if (++work->iter >= work->descr->max_iter) {
					seterr(&snmp_client,
					    "max iteration count exceeded");
					return (-1);
				}
				table_free(work, 1);
				return (-2);
			}
					
			continue;
		}
		if (!asn_is_suboid(&work->descr->table, &b->var) ||
		    b->syntax == SNMP_SYNTAX_ENDOFMIBVIEW)
			return (0);

		if ((e = table_find(work, &b->var)) == NULL)
			return (-1);
		if (table_value(work->descr, e, b))
			return (-1);
	}
	return (+1);
}
Esempio n. 3
0
void fs_binding_uniq(fs_binding *bi)
{
    if (fs_binding_length(bi) < 2) {
        /* we don't need to do anything, code below assumes >= 1 row */
        return;
    }

    fs_binding *b = fs_binding_copy_and_clear(bi);

    bi[0].vals->length = 0;

#ifdef DEBUG_MERGE
    double then = fs_time();
#endif
    int length = fs_binding_length(b);

    int outrow = 1;
    for (int column = 1; b[column].name; column++) {
        fs_rid_vector_append(bi[column].vals, table_value(b, column, 0));
        bi[column].bound = b[column].bound;
        b[column].sort = b[column].bound;
    }
    for (int row = 1; row < length; row++) {
	if (binding_row_compare(NULL, b, b, row, row-1, length, length) == 0) {
	    continue;
	}
	for (int column = 1; b[column].name; column++) {
            fs_rid_vector_append(bi[column].vals, table_value(b, column, row));
	}
	outrow++;
    }

#ifdef DEBUG_MERGE
    double now = fs_time();
    printf("uniq took %fs (%d->%d rows)\n", now-then, length, outrow);
    fs_binding_print(bi, stdout);
#endif
    fs_binding_free(b);
}
Esempio n. 4
0
fs_binding *fs_binding_join(fs_query *q, fs_binding *a, fs_binding *b, fs_join_type join)
{
    if (a == NULL) {
        return fs_binding_copy(b);
    }
    if (b == NULL) {
        return fs_binding_copy(a);
    }

    fs_binding *c = fs_binding_copy(a);
    int inter = 0;      /* do the tables intersect */

    for (int i=0; a[i].name; i++) {
	a[i].sort = 0;
	b[i].sort = 0;
	c[i].sort = 0;
        c[i].vals->length = 0;
    }
    int bound_a = 0;
    int bound_b = 0;
    for (int i=1; a[i].name; i++) {
        if (a[i].bound) bound_a++;
        if (b[i].bound) bound_b++;

        if (a[i].bound || b[i].bound) {
            c[i].bound = 1;
        }

	if (a[i].bound && b[i].bound) {
	    inter = 1;
	    a[i].sort = 1;
	    b[i].sort = 1;
#ifdef DEBUG_MERGE
            printf("joining on %s\n", a[i].name);
#endif
	}
    }

    /* a and b bound variables do not intersect, we can just dump results */
    if (!inter) {
        int length_a = fs_binding_length(a);
        int length_b = fs_binding_length(b);
	for (int i=1; a[i].name; i++) {
            if (!a[i].bound) {
                for (int j=0; j<length_a; j++) {
                    fs_rid_vector_append(c[i].vals, FS_RID_NULL);
                }
            } else {
                fs_rid_vector_append_vector(c[i].vals, a[i].vals);
            }
            if (!b[i].bound) {
                for (int j=0; j<length_b; j++) {
                    fs_rid_vector_append(c[i].vals, FS_RID_NULL);
                }
            } else {
                fs_rid_vector_append_vector(c[i].vals, b[i].vals);
            }
	}
#ifdef DEBUG_MERGE
        printf("append all, result:\n");
        fs_binding_print(c, stdout);
#endif
	return c;
    }

    int length_a = fs_binding_length(a);
    int length_b = fs_binding_length(b);

    /* sort the two sets of bindings so they can be merged linearly */
    fs_binding_sort(a);
    fs_binding_sort(b);

#ifdef DEBUG_MERGE
    printf("a: %d bindings\n", fs_binding_length(a));
    fs_binding_print(a, stdout);
    printf("b: %d bindings\n", fs_binding_length(b));
    fs_binding_print(b, stdout);
#endif

    /* If were running in restricted mode, truncate the binding tables */
    if (q->flags & FS_QUERY_RESTRICTED) {
        int restricted = 0;
        fs_binding_truncate(a, q->soft_limit);
        if (length_a > fs_binding_length(a)) {
            length_a = fs_binding_length(a);
            restricted = 1;
        }
        fs_binding_truncate(b, q->soft_limit);
        if (length_b > fs_binding_length(b)) {
            length_b = fs_binding_length(b);
            restricted = 1;
        }
        if (restricted) {
            char *msg = "some results have been dropped to prevent overunning effort allocation";
            q->warnings = g_slist_prepend(q->warnings, msg);
        }
    }

    int apos = 0;
    int bpos = 0;
    int cmp;
    while (apos < length_a) {
        if (join == FS_INNER && bpos >= length_b) break;
	cmp = binding_row_compare(q, a, b, apos, bpos, length_a, length_b);
        if (cmp == -1) {
            /* A and B aren't compatible, A sorts lower, skip A or left join */
#if DEBUG_MERGE > 1
            printf("[L] Ar=%d, Br=%d", apos, bpos);
#endif
            if (join == FS_LEFT) {
                for (int col=0; a[col].name; col++) {
                    if (!c[col].need_val) {
                        continue;
                    } else if (a[col].bound) {
#if DEBUG_MERGE > 1
                        printf(" %s=%016llx", c[col].name, table_value(a, col, apos));
#endif
                        fs_rid_vector_append(c[col].vals, table_value(a, col, apos));
                    } else {
#if DEBUG_MERGE > 1
                        printf(" %s=null", c[col].name);
#endif
                        fs_rid_vector_append(c[col].vals, FS_RID_NULL);
                    }
                }
            }
            apos++;
        } else if (cmp == 0 || cmp == -2 || cmp == 2) {
        /* Both rows are equal (cmp == 0), or one row is null (cmp == -2, 2) */
	    /* Both rows match, find out what combinations bind and produce them */
#if DEBUG_MERGE > 1
            printf("[I] Ar=%d, Br=%d", apos, bpos);
#endif
            int range_a = apos+1;
            int range_b = bpos+1;
            while (binding_row_compare(q, a, a, apos, range_a, length_a, length_a) == 0) range_a++;
            while (binding_row_compare(q, b, b, bpos, range_b, length_b, length_b) == 0) range_b++;
            int start_a = apos;
            int start_b = bpos;
            for (apos = start_a; apos<range_a; apos++) {
                for (bpos = start_b; bpos<range_b; bpos++) {
                    for (int col=0; a[col].name; col++) {
                        if (!c[col].need_val) {
                            continue;
                        } else if (!a[col].bound && !b[col].bound) {
#if DEBUG_MERGE > 1
                            printf(" %s=null", c[col].name);
#endif
                            fs_rid_vector_append(c[col].vals, FS_RID_NULL);
                        } else if (a[col].bound) {
                            /* if were left joining and A is NULL, we want the
                             * value from B */
                            if (join == FS_LEFT && table_value(a, col, apos) == FS_RID_NULL && b[col].bound) {
#if DEBUG_MERGE > 1
                                printf(" %s=%016llx", c[col].name, table_value(b, col, bpos));
#endif
                                fs_rid_vector_append(c[col].vals, table_value(b, col, bpos));
                            } else {
#if DEBUG_MERGE > 1
                                printf(" %s=%016llx", c[col].name, table_value(a, col, apos));
#endif
                                fs_rid_vector_append(c[col].vals, table_value(a, col, apos));
                            }
                        } else {
#if DEBUG_MERGE > 1
                            printf(" %s=%016llx", c[col].name, table_value(b, col, bpos));
#endif
                            fs_rid_vector_append(c[col].vals, table_value(b, col, bpos));
                        }
                    }
                }
            }
            /* this is actually unneccesary because the for loop will do the
             * same thing, but it's clearer */
            apos = range_a;
            bpos = range_b;
	} else if (cmp == +1) {
            /* A and B aren't compatible, B sorts lower, skip B */
            bpos++;
	} else {
            fs_error(LOG_ERR, "cmp=%d, value out of range", cmp);
        }
#if DEBUG_MERGE > 1
        printf("\n");
#endif
    }

    /* clear the _ord columns */
    a[0].vals->length = 0;
    b[0].vals->length = 0;

#ifdef DEBUG_MERGE
    printf("result: %d bindings\n", fs_binding_length(c));
    fs_binding_print(c, stdout);
#endif

    return c;
}
Esempio n. 5
0
/* return to = from [X] to, this is used to perform joins inside blocks, it
 * saves allocations by doing most operations inplace, unlike fs_binding_join */
void fs_binding_merge(fs_query *q, int block, fs_binding *from, fs_binding *to)
{
    fs_binding *inter_f = NULL; /* the intersecting column */
    fs_binding *inter_t = NULL; /* the intersecting column */

    for (int i=0; from[i].name; i++) {
	from[i].sort = 0;
	to[i].sort = 0;
    }
    int used = 0;
    for (int i=1; from[i].name; i++) {
	if (!from[i].bound || !to[i].bound) continue;
        if (from[i].used) used++;

	if (from[i].bound && to[i].bound) {
	    inter_f = from+i;
	    inter_t = to+i;
	    from[i].sort = 1;
	    to[i].sort = 1;
#ifdef DEBUG_MERGE
    printf("@@ join on %s\n", to[i].name);
#endif
	}
    }

    /* from and to bound variables do not intersect, we can just dump results,
       under some circustances we need to do a combinatorial explosion */
    if (!inter_f && (fs_binding_length(from) == 0)) {
	const int length_f = fs_binding_length(from);
	const int length_t = fs_binding_length(to);
	for (int i=1; from[i].name; i++) {
	    if (to[i].bound && !from[i].bound) {
                if (from[i].vals) {
                    fs_rid_vector_free(from[i].vals);
                }
		from[i].vals = fs_rid_vector_new(length_f);
		for (int d=0; d<length_f; d++) {
		    from[i].vals->data[d] = FS_RID_NULL;
		}
		from[i].bound = 1;
	    }
	    if (!from[i].bound) continue;
	    if (!to[i].bound) {
                if (to[i].vals) {
                    fs_rid_vector_free(to[i].vals);
                }
		to[i].vals = fs_rid_vector_new(length_t);
		for (int d=0; d<length_t; d++) {
                    to[i].vals->data[d] = FS_RID_NULL;
                }
	    }
	    fs_rid_vector_append_vector(to[i].vals, from[i].vals);
	    to[i].bound = 1;
	}
#ifdef DEBUG_MERGE
        printf("append all, result:\n");
        fs_binding_print(to, stdout);
#endif

	return;
    }

    /* If were running in restricted mode, truncate the binding tables */
    if (q->flags & FS_QUERY_RESTRICTED) {
        fs_binding_truncate(from, q->soft_limit);
        fs_binding_truncate(to, q->soft_limit);
    }

    int length_t = fs_binding_length(to);
    int length_f = fs_binding_length(from);
    /* ms8: this list keeps track of the vars to replace */
    GList *rep_list = NULL;
    for (int i=1; to[i].name; i++) {
	if (to+i == inter_t || to[i].used || to[i].bound) {
	    /* do nothing */
#if DEBUG_MERGE > 1
    printf("@@ preserve %s\n", to[i].name);
#endif
	} else if (from[i].bound && !to[i].bound) {
#if DEBUG_MERGE > 1
    printf("@@ replace %s\n", from[i].name);
#endif
	    to[i].bound = 1;
            if (to[i].vals) {
                if (to[i].vals->length != length_t) {
                    fs_rid_vector_free(to[i].vals);
                    to[i].vals = fs_rid_vector_new(length_t);
                }
            } else {
                to[i].vals = fs_rid_vector_new(length_t);
            }
	    for (int d=0; d<length_t; d++) {
		to[i].vals->data[d] = FS_RID_NULL;
	    }
        rep_list = g_list_append(rep_list, GINT_TO_POINTER(i));
	}
    }

    /* sort the two sets of bindings so they can be merged linearly */
    if (inter_f) {
        fs_binding_sort(from);
        fs_binding_sort(to);
    } else {
        /* make sure the tables are not marked sorted */
        from[0].vals->length = 0;
        to[0].vals->length = 0;
    }

#ifdef DEBUG_MERGE
    printf("old: %d bindings\n", fs_binding_length(from));
    fs_binding_print(from, stdout);
    printf("new: %d bindings\n", fs_binding_length(to));
    fs_binding_print(to, stdout);
#endif

    int fpos = 0;
    int tpos = 0;
    while (fpos < length_f || tpos < length_t) {
        if (q->flags & FS_QUERY_RESTRICTED &&
            fs_binding_length(to) >= q->soft_limit) {
            char *msg = g_strdup("some results have been dropped to prevent overunning time allocation");
            q->warnings = g_slist_prepend(q->warnings, msg);
            break;
        }
	int cmp;
	cmp = binding_row_compare(q, from, to, fpos, tpos, length_f, length_t);
	if (cmp == 0) {
	    /* both rows match */
	    int fp, tp = tpos;
	    for (fp = fpos; binding_row_compare(q, from, to, fp, tpos, length_f, length_t) == 0; fp++) {
#if DEBUG_MERGE > 1
if (fp == DEBUG_CUTOFF) {
    printf("...\n");
}
#endif
		for (tp = tpos; 1; tp++) {
		    if (binding_row_compare(q, from, to, fp, tp, length_f, length_t) == 0) {
#if DEBUG_MERGE > 1
if (fp < DEBUG_CUTOFF) {
    printf("STEP %d, %d  ", fp-fpos, tp-tpos);
}
#endif
			if (fp == fpos) {
#if DEBUG_MERGE > 1
if (fp < DEBUG_CUTOFF) {
    if (inter_f) {
	printf("REPL %llx\n", inter_f->vals->data[fp]);
    } else {
	printf("REPL ???\n");
    }
}
#endif
			    for (int c=1; to[c].name; c++) {
				if (!from[c].bound && !to[c].bound) continue;
				if (from[c].bound && table_value(from, c, fp) == FS_RID_NULL) {
				    continue;
				}
				if (from[c].bound && fp < from[c].vals->length) {
                                    long wrow = to[0].vals->length ? to[0].vals->data[tp] : tp;
				    to[c].vals->data[wrow] = table_value(from, c, fp);
				    if (to[c].vals->length <= tp) {
					to[c].vals->length = tp+1;
				    }
				}
			    }
			} else {
#if DEBUG_MERGE > 1
if (fp < DEBUG_CUTOFF) {
    printf("ADD\n");
}
#endif
			    for (int c=1; to[c].name; c++) {
				if (!from[c].bound && !to[c].bound) continue;
				if (from[c].bound && fp < from[c].vals->length) {
				    fs_rid_vector_append(to[c].vals, table_value(from, c, fp));
				} else {
				    fs_rid_vector_append(to[c].vals, table_value(to, c, tp));
				}
			    }
			}
		    } else {
			break;
		    }
		}
	    }
	    tpos = tp;
	    fpos = fp;
	} else if (cmp <= -1) {
	    fpos++;
	} else if (cmp >= 1) {
	    tpos++;
	} else {
	    fs_error(LOG_CRIT, "unknown compare state %d in binding", cmp);
	}
    }

    /* clear the _ord columns */
    from[0].vals->length = 0;
    to[0].vals->length = 0;

    /* ms8: INIT code to clean up rows that where not replaced */
    if (rep_list) {
        unsigned char *to_del = fs_new_bit_array(length_t);
        int to_del_count = 0;
        while(rep_list) {
            int col_r = GPOINTER_TO_INT(rep_list->data);
             rep_list = g_list_next(rep_list);
             for (int d=0; d<length_t; d++) {
                if (to[col_r].vals->data[d] == FS_RID_NULL) {
                     fs_bit_array_set(to_del, d, 0);
                     to_del_count++;
                }
             }
         }
         g_list_free(rep_list);
         if (to_del_count) {
             int vars = 0;
             for (int i=1; to[i].name; i++)
                vars++;
             fs_rid_vector **clean = calloc(vars, sizeof(fs_rid_vector *));
             for (int i=0;i<vars;i++)
                clean[i] = fs_rid_vector_new(0);
             for (int d = 0;d<length_t;d++) {
                   if (fs_bit_array_get(to_del,d)) {
                     for (int i=0;i<vars;i++) {
                        fs_rid_vector_append(clean[i],to[i+1].vals->data[d]);
                     }
                   }
             }
             for (int i=1;i<=vars;i++) {
                free(to[i].vals->data);
                to[i].vals->data = clean[i-1]->data;
                to[i].vals->length = clean[i-1]->length;
                to[i].vals->size = clean[i-1]->size;
                free(clean[i-1]);
             }
             free(clean);
         }
         fs_bit_array_destroy(to_del);
     }
    /* ms8: END code to clean up rows that where not replaced */

#ifdef DEBUG_MERGE
    printf("result: %d bindings\n", fs_binding_length(to));
    fs_binding_print(to, stdout);
#endif
}
Esempio n. 6
0
fs_binding *fs_binding_minus(fs_query *q, fs_binding *a, fs_binding *b)
{
    if (a == NULL) {
        return NULL;
    }
    if (b == NULL) {
        /* a - 0 = a */
        return fs_binding_copy(a);
    }

    fs_binding *c = fs_binding_copy(a);
    int inter = 0;      /* do the tables intersect */

    for (int i=0; a[i].name; i++) {
	a[i].sort = 0;
	b[i].sort = 0;
	c[i].sort = 0;
        c[i].vals->length = 0;
    }
    int bound_a = 0;
    int bound_b = 0;
    for (int i=1; a[i].name; i++) {
        if (a[i].bound) bound_a++;
        if (b[i].bound) bound_b++;

        if (a[i].bound || b[i].bound) {
            c[i].bound = 1;
        }

	if (a[i].bound && b[i].bound) {
	    inter = 1;
	    a[i].sort = 1;
	    b[i].sort = 1;
#ifdef DEBUG_MERGE
            printf("joining on %s\n", a[i].name);
#endif
	}
    }

    /* a and b bound variables do not intersect, return c (copy of a) */
    if (!inter) {
#ifdef DEBUG_MERGE
        printf("remove nothing, result:\n");
        fs_binding_print(c, stdout);
#endif
	return c;
    }

    int length_a = fs_binding_length(a);
    int length_b = fs_binding_length(b);

    /* sort the two sets of bindings so they can be merged linearly */
    fs_binding_sort(a);
    fs_binding_sort(b);

#ifdef DEBUG_MERGE
    printf("a: %d bindings\n", fs_binding_length(a));
    fs_binding_print(a, stdout);
    printf("b: %d bindings\n", fs_binding_length(b));
    fs_binding_print(b, stdout);
#endif

    int apos = 0;
    int bpos = 0;
    int cmp;
    while (apos < length_a) {
	cmp = binding_row_compare(q, a, b, apos, bpos, length_a, length_b);
        if (cmp == -1 || cmp == -2) {
            /* A and B aren't compatible, keep A row */
            for (int col=0; a[col].name; col++) {
                if (!c[col].need_val) {
                    continue;
                } else if (a[col].bound) {
                    fs_rid_vector_append(c[col].vals, table_value(a, col, apos));
                } else {
                    fs_rid_vector_append(c[col].vals, FS_RID_NULL);
                }
            }
            apos++;
        } else if (cmp == 0) {
            /* Both rows are equal (cmp == 0), skip A row in result */
#if DEBUG_MERGE > 1
            printf("[I] Ar=%d, Br=%d", apos, bpos);
#endif
            int range_a = apos+1;
            int range_b = bpos+1;
            while (binding_row_compare(q, a, a, apos, range_a, length_a, length_a) == 0) range_a++;
            while (binding_row_compare(q, b, b, bpos, range_b, length_b, length_b) == 0) range_b++;
            apos = range_a;
            bpos = range_b;
	} else if (cmp == +1 || cmp == +2) {
            /* A and B aren't compatible, B sorts lower, skip B or
               B row is NULL */
            bpos++;
	} else {
            fs_error(LOG_ERR, "cmp=%d, value out of range", cmp);
        }
    }

    /* clear the _ord columns */
    a[0].vals->length = 0;
    b[0].vals->length = 0;

#ifdef DEBUG_MERGE
    printf("result: %d bindings\n", fs_binding_length(c));
    fs_binding_print(c, stdout);
#endif

    return c;
}