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); }
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); }
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; }
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"); }
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"); }
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"); }
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)); }
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"); }
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"); }
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"); }
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); }
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"); }
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"); }
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; }
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"); }
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; }
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); }
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); }
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); }
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); }