コード例 #1
0
ファイル: filter.c プロジェクト: dajobe/4store
fs_value fn_less_than_equal(fs_query *q, fs_value a, fs_value b)
{
#if 0
fs_value_print(a);
printf(" <= ");
fs_value_print(b);
printf("\n");
#endif
    if (a.valid & fs_valid_bit(FS_V_TYPE_ERROR)) {
	return a;
    }
    if (b.valid & fs_valid_bit(FS_V_TYPE_ERROR)) {
	return b;
    }

    /* URIs and bNodes don't compare */
    if (FS_IS_URI_BN(a.rid) || FS_IS_URI_BN(b.rid)) {
        return fs_value_boolean(0);
    }

    /* If it's simply the same term it must be <= itsself */
    fs_value term_eq = fn_rdfterm_equal(q, a, b);
    if (term_eq.in == 1) {
        return term_eq;
    }

    if (a.attr == fs_c.xsd_datetime && b.attr == fs_c.xsd_datetime) return fn_not(q, fn_datetime_greater_than(q, a, b));
    if (fs_is_numeric(&a) && fs_is_numeric(&b)) return fn_logical_or(q, fn_numeric_less_than(q, a, b), fn_numeric_equal(q, a, b));

    if (a.lex && b.lex)
        return fn_not(q, fn_numeric_equal(q, fn_compare(q, a, b), fs_value_integer(1)));

    return fs_value_error(FS_ERROR_INVALID_TYPE, NULL);
}
コード例 #2
0
ファイル: filter.c プロジェクト: dajobe/4store
fs_value fn_equal(fs_query *q, fs_value a, fs_value b)
{
#if 0
fs_value_print(a);
printf(" = ");
fs_value_print(b);
printf("\n");
#endif
    if (a.valid & fs_valid_bit(FS_V_TYPE_ERROR)) {
	return a;
    }
    if (b.valid & fs_valid_bit(FS_V_TYPE_ERROR)) {
	return b;
    }

    fs_value term_equal = fn_rdfterm_equal(q, a, b);
    if (term_equal.in == 1) {
        return term_equal;
    }

    if (a.attr == fs_c.xsd_datetime)
        return fn_datetime_equal(q, a, b);
    if (fs_is_numeric(&a) && fs_is_numeric(&b))
        return fn_numeric_equal(q, a, b);

    if (FS_IS_LITERAL(a.rid) && FS_IS_LITERAL(b.rid) &&
        (a.attr == fs_c.empty || a.attr == fs_c.xsd_string) &&
        (b.attr == fs_c.empty || b.attr == fs_c.xsd_string)) {
        return fs_value_boolean(!strcmp(a.lex, b.lex));
    }

    return fs_value_boolean(0);
}
コード例 #3
0
ファイル: order.c プロジェクト: pombredanne/4store
static int orow_compare_sub(const struct order_row *a,
                            const struct order_row *b)
{
    int mod = 0;

    for (int i=0; i<a->width; i++) {
        fs_value va = a->vals[i];
        fs_value vb = b->vals[i];
        if (va.valid & fs_valid_bit(FS_V_DESC)) {
            mod = -1;
        } else {
            mod = 1;
        }
#ifdef DEBUG_ORDER
fs_value_print(va);
printf(" <=> ");
fs_value_print(vb);
#endif
        int order = fs_order_by_cmp(va, vb);
        if (order == 0) {
            continue;
        }

        return order * mod;
    }

    return 0;
}
コード例 #4
0
ファイル: filter.c プロジェクト: dajobe/4store
fs_value fn_numeric_equal(fs_query *q, fs_value a, fs_value b)
{
#if 0
fs_value_print(a);
printf(" ");
fs_value_print(b);
printf("\n");
#endif
    a = fs_value_promote(q, a, b);
    b = fs_value_promote(q, b, a);

    if (a.attr == b.attr && a.attr != FS_RID_NULL && a.attr != fs_c.empty) {
	if (a.attr == fs_c.xsd_double || a.attr == fs_c.xsd_float) {
	    return fs_value_boolean(a.fp == b.fp);
	}
	if (a.attr == fs_c.xsd_decimal) {
	    return fs_value_boolean(fs_decimal_equal(&a.de, &b.de));
	}
	if (a.attr == fs_c.xsd_integer) {
	    return fs_value_boolean(a.in == b.in);
	}
	if (a.attr == fs_c.xsd_boolean) {
	    return fs_value_boolean((a.in ? 1 : 0) == (b.in ? 1 : 0));
	}
    }

    return fs_value_error(FS_ERROR_INVALID_TYPE, "non-numeric arguments to fn:numeric-equal");
}
コード例 #5
0
ファイル: filter.c プロジェクト: dajobe/4store
fs_value fn_numeric_less_than(fs_query *q, fs_value a, fs_value b)
{
    a = fs_value_promote(q, a, b);
    b = fs_value_promote(q, b, a);
#if 0
fs_value_print(a);
printf(" < ");
fs_value_print(b);
printf("\n");
#endif

    if (a.attr == b.attr && a.attr != FS_RID_NULL && a.attr != fs_c.empty) {
	if (a.attr == fs_c.xsd_double || a.attr == fs_c.xsd_float) {
	    return fs_value_boolean(a.fp < b.fp);
	}
	if (a.attr == fs_c.xsd_decimal) {
	    return fs_value_boolean(fs_decimal_less_than(&a.de, &b.de));
	}
	if (a.attr == fs_c.xsd_integer) {
	    return fs_value_boolean(a.in < b.in);
	}
    }

    return fs_value_error(FS_ERROR_INVALID_TYPE, "non-numeric arguments to fn:numeric-less-than");
}
コード例 #6
0
ファイル: filter.c プロジェクト: nakao/4store
fs_value fn_datetime_less_than(fs_query *q, fs_value a, fs_value b)
{
#if 0
fs_value_print(a);
printf(" < ");
fs_value_print(b);
printf(" [dT]\n");
#endif
    if (a.attr == fs_c.xsd_datetime && b.attr == fs_c.xsd_datetime)
	return fs_value_boolean(a.in < b.in);

    return fs_value_error(FS_ERROR_INVALID_TYPE, "bad arguments to fn:datetime-less-than");
}
コード例 #7
0
ファイル: filter.c プロジェクト: dajobe/4store
fs_value fn_not_equal(fs_query *q, fs_value a, fs_value b)
{
#if 0
fs_value_print(a);
printf(" != ");
fs_value_print(b);
printf("\n");
#endif
    if (a.valid & fs_valid_bit(FS_V_TYPE_ERROR)) {
	return a;
    }
    if (b.valid & fs_valid_bit(FS_V_TYPE_ERROR)) {
	return b;
    }

    if (a.attr == fs_c.xsd_datetime)
        return fn_not(q, fn_datetime_equal(q, a, b));

    if (fs_is_numeric(&a) && fs_is_numeric(&b))
        return fn_not(q, fn_numeric_equal(q, a, b));

    if ((a.attr == fs_c.empty || a.attr == fs_c.xsd_string) &&
        (b.attr == fs_c.empty || b.attr == fs_c.xsd_string)) {
        return fs_value_boolean(strcmp(a.lex, b.lex));
    }

    if ((FS_IS_URI_BN(a.rid) && FS_IS_LITERAL(b.rid)) ||
        (FS_IS_LITERAL(a.rid) && FS_IS_URI_BN(b.rid))) {
        /* ones a URI/bNode and ones a literal, definatly different */
        return fs_value_boolean(1);
    }

    if ((!FS_IS_URI(a.rid) && a.attr != fs_c.empty && FS_IS_LITERAL(a.attr) &&
         !FS_IS_LITERAL(b.attr)) ||
        (!FS_IS_URI(a.rid) && !FS_IS_LITERAL(a.attr) && b.attr != fs_c.empty &&
         FS_IS_LITERAL(b.attr))) {
        /* one has a lang tag and one doesn't, definatly different */
        return fs_value_boolean(1);
    }

    if (FS_IS_URI(a.attr) || FS_IS_URI(b.attr)) {
        /* at least one argument has an unknown datatype */
        return fs_value_boolean(0);
    }

    return fn_not(q, fn_rdfterm_equal(q, a, b));
}
コード例 #8
0
ファイル: filter.c プロジェクト: dajobe/4store
fs_value fn_datetime_less_than(fs_query *q, fs_value a, fs_value b)
{
#if 0
fs_value_print(a);
printf(" < ");
fs_value_print(b);
printf(" [dT]\n");
#endif
    if (a.attr == fs_c.xsd_datetime && b.attr == fs_c.xsd_datetime &&
        (a.in != -1 || b.in != -1))
	return fs_value_boolean(a.in < b.in);

    if (a.lex && b.lex) {
        return fs_value_boolean(iso8601_compare(a.lex, b.lex) == -1);
    }

    return fs_value_error(FS_ERROR_INVALID_TYPE, "bad arguments to fn:datetime-less-than");
}
コード例 #9
0
ファイル: filter.c プロジェクト: dajobe/4store
fs_value fn_cast(fs_query *q, fs_value v, fs_value d)
{
#if 0
printf("CAST ");
fs_value_print(v);
printf(" -> ");
fs_value_print(d);
printf("\n");
#endif
    if (FS_IS_URI(d.rid) && FS_IS_LITERAL(v.rid)) {
	return fn_cast_intl(q, v, d.rid);
    }
    if (d.rid == fs_c.xsd_string && FS_IS_URI(v.rid)) {
        fs_value v2 = fn_cast_intl(q, v, d.rid);
        v2.rid = fs_hash_literal(v.lex, d.rid);
	return v2;
    }

    return fs_value_error(FS_ERROR_INVALID_TYPE, "cast on URI/bNode");
}
コード例 #10
0
ファイル: filter.c プロジェクト: dajobe/4store
fs_value fn_plus(fs_query *q, fs_value a)
{
#if 0
fs_value_print(a);
#endif
    if (fs_is_numeric(&a)) {
        return a;
    }

    return fs_value_error(FS_ERROR_INVALID_TYPE, "bad arguments to fn:plus");
}
コード例 #11
0
ファイル: filter.c プロジェクト: nakao/4store
fs_value fn_less_than(fs_query *q, fs_value a, fs_value b)
{
    if (a.valid & fs_valid_bit(FS_V_TYPE_ERROR)) {
	return a;
    }
    if (b.valid & fs_valid_bit(FS_V_TYPE_ERROR)) {
	return b;
    }
#if 0
fs_value_print(a);
printf(" < ");
fs_value_print(b);
printf("\n");
#endif

    if (a.attr == fs_c.xsd_datetime && b.attr == fs_c.xsd_datetime) return fn_datetime_less_than(q, a, b);
    if (fs_is_numeric(&a)) return fn_numeric_less_than(q, a, b);
    if (a.lex && b.lex) return fn_numeric_equal(q, fn_compare(q, a, b), fs_value_integer(-1));

    return fs_value_error(FS_ERROR_INVALID_TYPE, NULL);
}
コード例 #12
0
ファイル: filter.c プロジェクト: dajobe/4store
fs_value fn_compare(fs_query *q, fs_value a, fs_value b)
{
    if (a.valid & fs_valid_bit(FS_V_TYPE_ERROR)) {
	return a;
    }
    if (b.valid & fs_valid_bit(FS_V_TYPE_ERROR)) {
	return b;
    }

#if 0
fs_value_print(a);
printf(" <=> ");
fs_value_print(b);
printf("\n");
#endif
    if ((FS_IS_LITERAL(a.attr) && FS_IS_LITERAL(b.attr)) ||
	(a.attr == fs_c.empty && b.attr == fs_c.empty)) {
	if (a.lex && b.lex) {
	    int diff = strcmp(a.lex, b.lex);
	    if (diff > 0) {
		return fs_value_integer(1);
	    } else if (diff < 0) {
		return fs_value_integer(-1);
	    }
	    return fs_value_integer(0);
	}
    } else if (a.attr == fs_c.xsd_string && b.attr == fs_c.xsd_string) {
	if (a.lex && b.lex) {
	    int diff = strcmp(a.lex, b.lex);
	    if (diff > 0) {
		return fs_value_integer(1);
	    } else if (diff < 0) {
		return fs_value_integer(-1);
	    }
	    return fs_value_integer(0);
	}
    }

    return fs_value_error(FS_ERROR_INVALID_TYPE, "bad arguments to fn:compare");
}
コード例 #13
0
ファイル: filter.c プロジェクト: dajobe/4store
fs_value fn_numeric_add(fs_query *q, fs_value a, fs_value b)
{
#if 0
fs_value_print(a);
printf(" + ");
fs_value_print(b);
printf("\n");
#endif
    a = fs_value_promote(q, a, b);
    b = fs_value_promote(q, b, a);
#if 0
fs_value_print(a);
printf(" P+ ");
fs_value_print(b);
printf("\n");
#endif

    if (a.attr == b.attr && a.attr != FS_RID_NULL && a.attr != fs_c.empty) {
	fs_value v = fs_value_blank();
	v.attr = a.attr;
	if (a.attr == fs_c.xsd_double || a.attr == fs_c.xsd_float) {
	    v.fp = a.fp + b.fp;
	    v.valid = fs_valid_bit(FS_V_FP);

	    return v;
	} else if (a.attr == fs_c.xsd_decimal) {
            fs_decimal_add(&a.de, &b.de, &v.de);
	    v.valid = fs_valid_bit(FS_V_DE);

	    return v;
	} else if (a.attr == fs_c.xsd_integer) {
	    v.in = a.in + b.in;
	    v.valid = fs_valid_bit(FS_V_IN);

	    return v;
	}
    }

    return fs_value_error(FS_ERROR_INVALID_TYPE, "non-numeric arguments to fn:add");
}
コード例 #14
0
ファイル: query-datatypes.c プロジェクト: LeifW/4store
fs_binding *fs_binding_apply_filters(fs_query *q, int block, fs_binding *b, raptor_sequence *constr)
{
    fs_binding *ret = fs_binding_copy(b);
    if (!constr) {
        /* if there's no constriants then we don't need to do anything */

        return ret;
    }
    for (int col=0; b[col].name; col++) {
        ret[col].vals->length = 0;
    }
    int length = fs_binding_length(b);
    fs_binding *restore = q->bt;
    q->bt = b;
    /* TODO should prefetch lexical vals here */
    /* expressions that have been optimised out will be replaces with NULL,
     * so we have to be careful here */
/* --------------------------- */
/* PREFETCH should go here XXX */
/* --------------------------- */
    for (int row=0; row<length; row++) {
        for (int c=0; c<raptor_sequence_size(constr); c++) {
            rasqal_expression *e =
                raptor_sequence_get_at(constr, c);
            if (!e) continue;

            fs_value v = fs_expression_eval(q, row, block, e);
#ifdef DEBUG_FILTER
            rasqal_expression_print(e, stdout);
            printf(" -> ");
            fs_value_print(v);
            printf("\n");
#endif
            if (v.valid & fs_valid_bit(FS_V_TYPE_ERROR) && v.lex) {
                q->warnings = g_slist_prepend(q->warnings, v.lex);
            }
            fs_value result = fn_ebv(v);
            /* its EBV is not true, so we skip to the next one */
            if (result.valid & fs_valid_bit(FS_V_TYPE_ERROR) || !result.in) {
                continue;
            }
            for (int col=0; b[col].name; col++) {
                if (b[col].bound) {
                    fs_rid_vector_append(ret[col].vals, b[col].vals->data[row]);
                }
            }
        }
    }
    q->bt = restore;

    return ret;
}
コード例 #15
0
ファイル: filter.c プロジェクト: dajobe/4store
fs_value fn_datatype(fs_query *q, fs_value a)
{
#if 0
printf("datatype(");
fs_value_print(a);
printf(")\n");
#endif
    if (a.valid & fs_valid_bit(FS_V_TYPE_ERROR)) {
	return a;
    }

    if (a.valid & fs_valid_bit(FS_V_RID) && FS_IS_URI_BN(a.rid)) {
	return fs_value_error(FS_ERROR_INVALID_TYPE, NULL);
    }

    if (a.attr == FS_RID_NULL) {
	return fs_value_error(FS_ERROR_INVALID_TYPE, NULL);
    }

    if (FS_IS_LITERAL(a.attr) && a.attr != fs_c.empty) {
	return fs_value_error(FS_ERROR_INVALID_TYPE, NULL);
    } else {
	if (a.attr == fs_c.xsd_string || a.attr == fs_c.empty) {
	    return fs_value_uri(XSD_STRING);
	} else if (a.attr == fs_c.xsd_double) {
	    return fs_value_uri(XSD_DOUBLE);
	} else if (a.attr == fs_c.xsd_float) {
	    return fs_value_uri(XSD_FLOAT);
	} else if (a.attr == fs_c.xsd_decimal) {
	    return fs_value_uri(XSD_DECIMAL);
	} else if (a.attr == fs_c.xsd_integer) {
	    return fs_value_uri(XSD_INTEGER);
	} else if (a.attr == fs_c.xsd_boolean) {
	    return fs_value_uri(XSD_BOOLEAN);
	} else if (a.attr == fs_c.xsd_datetime) {
	    return fs_value_uri(XSD_DATETIME);
	}
    }

    fs_rid_vector *r = fs_rid_vector_new(1);
    r->data[0] = a.attr;
    fs_resource res;
    if (fs_query_link(q)) {
        fsp_resolve(fs_query_link(q), FS_RID_SEGMENT(a.attr,
                    fsp_link_segments(fs_query_link(q))), r, &res);
        fs_rid_vector_free(r);

        return fs_value_uri(res.lex);
    }

    return fs_value_uri("error:unresloved");
}
コード例 #16
0
fs_resource *fs_resource_value(fs_query *q, fs_value v)
{
    v = fs_value_fill_lexical(q, v);
    v = fs_value_fill_rid(q, v);
#if DEBUG_FILTER
    printf("resource->value ");
    fs_value_print(v);
    printf("\n");
#endif
    fs_resource *res = malloc(sizeof(fs_resource));
    res->rid = v.rid;
    res->attr = v.attr;
    res->lex = strdup(v.lex);

    return res;
}
コード例 #17
0
ファイル: order.c プロジェクト: pombredanne/4store
void fs_values_order(fs_query *q) {
    int conditions;
    for (conditions = 0; rasqal_query_get_order_condition(q->rq, conditions);
            conditions++); 
    int length = q->agg_values->len;
    fs_value *ordervals = malloc(length * conditions * sizeof(fs_value));
    struct order_row *orows = malloc(sizeof(struct order_row) * length);
    for (int i=0; i<length; i++) {
	for (int j=0; j<conditions; j++) {
	    ordervals[i * conditions + j] = fs_expression_eval(q, i, 0,
				rasqal_query_get_order_condition(q->rq, j));

#ifdef DEBUG_ORDER
printf("@@_ ORDER VAL (%d, %d) = ", i, j);
fs_value_print(ordervals[i * conditions + j]);
printf("\n");
#endif
	}
        orows[i].row = i;
        orows[i].width = conditions;
        orows[i].vals = ordervals + (i * conditions);
    }

    qsort(orows, length, sizeof(struct order_row), orow_compare);

    int *ordering = malloc(sizeof(int) * length);
    for (int i=0; i<length; i++) {
        ordering[i] = orows[i].row;
    }
#ifdef DEBUG_ORDER
printf("Output order:\n");
for (int i=0; i<length; i++) {
    printf("output row %d row %d\n", i, ordering[i]);
}
#endif

    q->ordering = ordering;
    free(ordervals);
    free(orows);
}
コード例 #18
0
ファイル: filter.c プロジェクト: dajobe/4store
fs_value fn_not(fs_query *q, fs_value a)
{
#if 0
printf("! ");
fs_value_print(a);
printf("\n");
#endif
    if (fs_is_error(a)) {
	return a;
    }
    if (a.valid & fs_valid_bit(FS_V_RID) && a.rid == FS_RID_NULL) {
	return fs_value_error(FS_ERROR_INVALID_TYPE, NULL);
    }

    fs_value ebv = fn_ebv(a);

    if (fs_is_error(ebv)) {
	return ebv;
    }

    return fs_value_boolean(!ebv.in);
}
コード例 #19
0
ファイル: order.c プロジェクト: pombredanne/4store
void fs_query_order(fs_query *q)
{
    int conditions;

    for (conditions = 0; rasqal_query_get_order_condition(q->rq, conditions);
            conditions++);
    const int length = q->length;
#ifdef DEBUG_ORDER
printf("@@ ORDER (%d x %d)\n", conditions, length);
#endif

    /* trap trivial cases */
    if (conditions == 0 || length == 0) {
        return;
    }

    /* spot the case where we have ORDER BY ?x, saves evaluating expressions */
    if (conditions == 1) {
        rasqal_expression *oe = rasqal_query_get_order_condition(q->rq, 0);
        if ((oe->op == RASQAL_EXPR_ORDER_COND_ASC ||
             oe->op == RASQAL_EXPR_ORDER_COND_DESC) &&
            oe->arg1->op == RASQAL_EXPR_LITERAL &&
            oe->arg1->literal->type == RASQAL_LITERAL_VARIABLE) {
            long int col = (long int)oe->arg1->literal->value.variable->user_data;
            if (col == 0) {
                fs_error(LOG_CRIT, "missing column");

                return;
            }
            int *ordering;
            if (!fs_sort_column(q, q->bt, col, &ordering)) {
                if (oe->op == RASQAL_EXPR_ORDER_COND_DESC) {
                    reverse_array(ordering, q->bt[col].vals->length);
                }
                q->ordering = ordering;

                return;
            }
        }
    }

    struct order_row *orows = malloc(sizeof(struct order_row) * length);
    fs_value *ordervals = malloc(length * conditions * sizeof(fs_value));
    for (int i=0; i<length; i++) {
	for (int j=0; j<conditions; j++) {
	    ordervals[i * conditions + j] = fs_expression_eval(q, i, 0,
				rasqal_query_get_order_condition(q->rq, j));

#ifdef DEBUG_ORDER
printf("@@ ORDER VAL (%d, %d) = ", i, j);
fs_value_print(ordervals[i * conditions + j]);
printf("\n");
#endif
	}
        orows[i].row = i;
        orows[i].width = conditions;
        orows[i].vals = ordervals + (i * conditions);
    }

    qsort(orows, length, sizeof(struct order_row), orow_compare);

    int *ordering = malloc(sizeof(int) * length);
    for (int i=0; i<length; i++) {
        ordering[i] = orows[i].row;
    }
#ifdef DEBUG_ORDER
printf("Output order:\n");
for (int i=0; i<length; i++) {
    printf("output row %d row %d\n", i, ordering[i]);
}
#endif

    q->ordering = ordering;
    free(ordervals);
    free(orows);
}
コード例 #20
0
ファイル: filter.c プロジェクト: dajobe/4store
fs_value fn_matches(fs_query *q, fs_value str, fs_value pat, fs_value flags)
{
    if (str.valid & fs_valid_bit(FS_V_TYPE_ERROR)) {
	return str;
    }
    if (pat.valid & fs_valid_bit(FS_V_TYPE_ERROR)) {
	return pat;
    }
    if (flags.valid & fs_valid_bit(FS_V_TYPE_ERROR)) {
	return flags;
    }

    if (!str.lex || !pat.lex) {
	return fs_value_error(FS_ERROR_INVALID_TYPE,
                              "argument to fn:matches has no lexical value");
    }

    if (str.valid & fs_valid_bit(FS_V_RID) && FS_IS_URI(str.rid)) {
	return fs_value_error(FS_ERROR_INVALID_TYPE, NULL);
    }
#if 0
printf("REGEX ");
fs_value_print(str);
printf(", ");
fs_value_print(pat);
printf(", ");
fs_value_print(flags);
printf("\n");
#endif

    int reflags = PCRE_UTF8;
    if (flags.lex) {
	for (char *c = flags.lex; *c; c++) {
	    switch (*c) {
		case 's':
		    reflags |= PCRE_DOTALL;
		    break;
		case 'm':
		    reflags |= PCRE_MULTILINE;
		    break;
		case 'i':
		    reflags |= PCRE_CASELESS;
		    break;
		case 'x':
		    reflags |= PCRE_EXTENDED;
		    break;
		default:
		    fs_error(LOG_ERR, "unknown regex flag '%c'", *c);
		    return fs_value_error(FS_ERROR_INVALID_TYPE, "unrecognised flag in fn:matches");
	    }
	}
    }

    const char *error;
    int erroroffset;
    pcre *re = pcre_compile(pat.lex, reflags, &error, &erroroffset, NULL);
    if (!re) {
        return fs_value_error(FS_ERROR_INVALID_TYPE, error);
    }
    int rc = pcre_exec(re, NULL, str.lex, strlen(str.lex), 0, 0, NULL, 0);
    if (rc == PCRE_ERROR_NOMATCH) {
	return fs_value_boolean(0);
    }
    if (rc < 0) {
        fs_error(LOG_ERR, "internal error %d in pcre_exec", rc);

	return fs_value_error(FS_ERROR_INVALID_TYPE, "internal error in fn:matches");
    }

    return fs_value_boolean(1);
}