Skip to content

Commit

Permalink
Merge pull request #30 from davechallis/master
Browse files Browse the repository at this point in the history
Added support for FLOOR(), CEIL() and ROUND() SPARQL 1.1 keywords
  • Loading branch information
garlik committed Jun 14, 2011
2 parents 4d6657b + ef1b71f commit d35139a
Show file tree
Hide file tree
Showing 13 changed files with 420 additions and 23 deletions.
25 changes: 25 additions & 0 deletions data/numbers.ttl
Expand Up @@ -23,3 +23,28 @@
<p> <test:num> "12345678901234567890.23239300"^^xsd:float .
<q> <test:num> "-12345678901234567890.23239300"^^xsd:float .
<r> <test:num> "+12345678901234567890.23239300"^^xsd:float .

<s> <test:num> "2.4999"^^xsd:decimal .
<t> <test:num> "2.5"^^xsd:decimal .
<u> <test:num> "-2.5"^^xsd:decimal .
<v> <test:num> "-2.500001"^^xsd:decimal .
<w> <test:num> "2.500001"^^xsd:decimal .
<x> <test:num> "-2.499999"^^xsd:decimal .

<y> <test:num> "0000.0004999000"^^xsd:decimal .
<z> <test:num> "2.000050000"^^xsd:decimal .
<za> <test:num> "-2.00050000"^^xsd:decimal .

<zb> <test:num> "2.4999"^^xsd:float .
<zc> <test:num> "2.5"^^xsd:float .
<zd> <test:num> "-2.5"^^xsd:float .
<ze> <test:num> "-2.500001"^^xsd:float .
<zf> <test:num> "2.500001"^^xsd:float .
<zg> <test:num> "-2.499999"^^xsd:float .

<zh> <test:num> "2.4999"^^xsd:double .
<zi> <test:num> "2.5"^^xsd:double .
<zj> <test:num> "-2.5"^^xsd:double .
<zk> <test:num> "-2.500001"^^xsd:double .
<zl> <test:num> "2.500001"^^xsd:double .
<zm> <test:num> "-2.499999"^^xsd:double .
4 changes: 4 additions & 0 deletions src/frontend/decimal.h
Expand Up @@ -45,6 +45,10 @@ int fs_decimal_to_double(const fs_decimal *d, double *fp);
/* convert decimal value into nearest int represenation, non 0 on failure */
int fs_decimal_to_int64(const fs_decimal *d, int64_t *in);

/* copy one decimal to another */
void fs_decimal_copy(const fs_decimal *from, fs_decimal *to);


/* comparison functions */

/* return true if the two decimals compare equal */
Expand Down
176 changes: 175 additions & 1 deletion src/frontend/filter.c
Expand Up @@ -279,7 +279,7 @@ fs_value fn_minus(fs_query *q, fs_value a)
fs_value fn_numeric_abs(fs_query *q, fs_value a)
{
if (!fs_is_numeric(&a)) {
return fs_value_error(FS_ERROR_INVALID_TYPE, "non-numeric arguments to fn:abs");
return fs_value_error(FS_ERROR_INVALID_TYPE, "non-numeric argument to fn:abs");
}

if (a.attr == fs_c.xsd_double || a.attr == fs_c.xsd_float) {
Expand All @@ -303,6 +303,180 @@ fs_value fn_numeric_abs(fs_query *q, fs_value a)
return a;
}

fs_value fn_numeric_floor(fs_query *q, fs_value a)
{
if (!fs_is_numeric(&a)) {
return fs_value_error(FS_ERROR_INVALID_TYPE, "non-numeric argument to fn:floor");
}

if (a.attr == fs_c.xsd_integer) {
/* do nothing for integers */
return a;
}

if (a.attr == fs_c.xsd_double || a.attr == fs_c.xsd_float) {
a.fp = floor(a.fp);
} else if (a.attr == fs_c.xsd_decimal) {
fs_decimal r;

if (fs_decimal_less_than(&a.de, fs_decimal_zero)) {
fs_decimal one;
fs_decimal_init_from_double(&one, (double)1.0);
fs_decimal_subtract(&a.de, &one, &r);
}
else {
fs_decimal_copy(&a.de, &r);
}

for (int i=FS_D_OVER_DIGITS+FS_D_INT_DIGITS; i < FS_D_DIGITS; i++) {
r.digit[i] = 0;
}

fs_decimal_copy(&r, &a.de);
} else {
return fs_value_error(FS_ERROR_INVALID_TYPE, "bad arguments to fn:floor");
}

if (a.lex != NULL) {
a.lex = NULL;
}

return a;
}

fs_value fn_numeric_ceil(fs_query *q, fs_value a)
{
if (!fs_is_numeric(&a)) {
return fs_value_error(FS_ERROR_INVALID_TYPE, "non-numeric argument to fn:ceil");
}

if (a.attr == fs_c.xsd_integer) {
/* do nothing for integers */
return a;
}

if (a.attr == fs_c.xsd_double || a.attr == fs_c.xsd_float) {
a.fp = ceil(a.fp);
} else if (a.attr == fs_c.xsd_decimal) {
fs_decimal r;

if (fs_decimal_greater_than(&a.de, fs_decimal_zero)) {
fs_decimal one;
fs_decimal_init_from_double(&one, (double)1.0);
fs_decimal_add(&a.de, &one, &r);
}
else {
fs_decimal_copy(&a.de, &r);
}

for (int i=FS_D_OVER_DIGITS+FS_D_INT_DIGITS; i < FS_D_DIGITS; i++) {
r.digit[i] = 0;
}

fs_decimal_copy(&r, &a.de);
} else {
return fs_value_error(FS_ERROR_INVALID_TYPE, "bad arguments to fn:ceil");
}

if (a.lex != NULL) {
a.lex = NULL;
}

return a;
}

fs_value fn_numeric_round(fs_query *q, fs_value a)
{
if (!fs_is_numeric(&a)) {
return fs_value_error(FS_ERROR_INVALID_TYPE, "non-numeric argument to fn:round");
}

if (a.attr == fs_c.xsd_integer) {
/* do nothing for integers */
return a;
}

if (a.attr == fs_c.xsd_double || a.attr == fs_c.xsd_float) {
if (a.fp > 0.0) {
/* rounding +ve numbers same as c round */
a.fp = round(a.fp);
}
else if (a.fp < 0.0) {
/* -2.5 should round to -2.0 */
double i;
double f = modf(a.fp, &i);
a.fp -= f;
if (f < -0.5) {
a.fp -= 1.0;
}
}
} else if (a.attr == fs_c.xsd_decimal) {
/* 0 = round to num, e.g. 2.x -> 2.0, -2.x -> -2.0
1 = round away from num, e.g. 2.x -> 3.0, -2.x -> -3.0 */
int round_dir = -1;
int positive = fs_decimal_greater_than_equal(&a.de, fs_decimal_zero);

int start_pos = FS_D_OVER_DIGITS+FS_D_INT_DIGITS;
if ((&a.de)->digit[start_pos] > 5) {
round_dir = 1;
} else if ((&a.de)->digit[start_pos] < 5) {
round_dir = 0;
} else {
/* first digit should be a 5 */
for (int i=start_pos+1; i < FS_D_DIGITS; i++) {
if ((&a.de)->digit[i] > 0) {
/* abs(fractional part) is > 0.5 */
round_dir = 1;
break;
}
}

if (round_dir == -1) {
/* abs(fractional part) == 0.5, round depending on sign */
if (positive) {
round_dir = 1;
}
else {
round_dir = 0;
}
}
}

fs_decimal one;
fs_decimal_init_from_double(&one, (double)1.0);
fs_decimal r;

if (round_dir == 1) {
/* Round integral part of number away from zero */
if (positive) {
fs_decimal_add(&a.de, &one, &r);
}
else {
fs_decimal_subtract(&a.de, &one, &r);
}
}
else {
/* Keep integral part of number unchanged */
fs_decimal_copy(&a.de, &r);
}

/* Zero all fractional digits of number */
for (int i=start_pos; i < FS_D_DIGITS; i++) {
r.digit[i] = 0;
}

fs_decimal_copy(&r, &a.de);
} else {
return fs_value_error(FS_ERROR_INVALID_TYPE, "bad arguments to fn:round");
}

if (a.lex != NULL) {
a.lex = NULL;
}

return a;
}

fs_value fn_numeric_add(fs_query *q, fs_value a, fs_value b)
{
#if 0
Expand Down
7 changes: 6 additions & 1 deletion src/frontend/filter.h
Expand Up @@ -22,8 +22,13 @@ fs_value fn_greater_than(fs_query *q, fs_value a, fs_value b);
fs_value fn_less_than_equal(fs_query *q, fs_value a, fs_value b);
fs_value fn_greater_than_equal(fs_query *q, fs_value a, fs_value b);

/* binary maths operators */
/* unary maths operators */
fs_value fn_numeric_abs(fs_query *q, fs_value a);
fs_value fn_numeric_round(fs_query *q, fs_value a);
fs_value fn_numeric_ceil(fs_query *q, fs_value a);
fs_value fn_numeric_floor(fs_query *q, fs_value a);

/* binary maths operators */
fs_value fn_numeric_add(fs_query *q, fs_value a, fs_value b);
fs_value fn_numeric_subtract(fs_query *q, fs_value a, fs_value b);
fs_value fn_numeric_multiply(fs_query *q, fs_value a, fs_value b);
Expand Down
6 changes: 6 additions & 0 deletions src/frontend/results.c
Expand Up @@ -243,6 +243,12 @@ fs_value fs_expression_eval(fs_query *q, int row, int block, rasqal_expression *
#if RASQAL_VERSION >= 925
case RASQAL_EXPR_ABS:
return fn_numeric_abs(q, fs_expression_eval(q, row, block, e->arg1));
case RASQAL_EXPR_ROUND:
return fn_numeric_round(q, fs_expression_eval(q, row, block, e->arg1));
case RASQAL_EXPR_CEIL:
return fn_numeric_ceil(q, fs_expression_eval(q, row, block, e->arg1));
case RASQAL_EXPR_FLOOR:
return fn_numeric_floor(q, fs_expression_eval(q, row, block, e->arg1));
#endif
case RASQAL_EXPR_AND:
return fn_logical_and(q, fs_expression_eval(q, row, block, e->arg1),
Expand Down
61 changes: 41 additions & 20 deletions tests/httpd/exemplar/functions-abs
@@ -1,24 +1,45 @@
201 imported successfully
This is a 4store SPARQL server [VERSION]
Query: SELECT ?s (ABS(?d) AS ?abs_d) WHERE { ?s <test:num> ?d . } ORDER BY ?s
?s ?abs_d
<http://example.com/a> "0"^^<http://www.w3.org/2001/XMLSchema#integer>
<http://example.com/b> "0"^^<http://www.w3.org/2001/XMLSchema#integer>
<http://example.com/c> "0"^^<http://www.w3.org/2001/XMLSchema#integer>
<http://example.com/d> "1234"^^<http://www.w3.org/2001/XMLSchema#integer>
<http://example.com/e> "1234"^^<http://www.w3.org/2001/XMLSchema#integer>
<http://example.com/f> "1234"^^<http://www.w3.org/2001/XMLSchema#integer>
<http://example.com/g> "1234567890123456789"^^<http://www.w3.org/2001/XMLSchema#integer>
<http://example.com/h> "1234567890123456789"^^<http://www.w3.org/2001/XMLSchema#integer>
<http://example.com/i> "1234567890123456789"^^<http://www.w3.org/2001/XMLSchema#integer>
<http://example.com/j> "1234567890.232393"^^<http://www.w3.org/2001/XMLSchema#decimal>
<http://example.com/k> "1234567890.232393"^^<http://www.w3.org/2001/XMLSchema#decimal>
<http://example.com/l> "1234567890.232393"^^<http://www.w3.org/2001/XMLSchema#decimal>
<http://example.com/m> "inf"^^<http://www.w3.org/2001/XMLSchema#float>
<http://example.com/n> "inf"^^<http://www.w3.org/2001/XMLSchema#float>
<http://example.com/o> "inf"^^<http://www.w3.org/2001/XMLSchema#float>
<http://example.com/p> "1.23457e+19"^^<http://www.w3.org/2001/XMLSchema#float>
<http://example.com/q> "1.23457e+19"^^<http://www.w3.org/2001/XMLSchema#float>
<http://example.com/r> "1.23457e+19"^^<http://www.w3.org/2001/XMLSchema#float>
Query: SELECT ?s ?d (ABS(?d) AS ?abs_d) WHERE { ?s <test:num> ?d . } ORDER BY ?s
?s ?d ?abs_d
<http://example.com/a> "0"^^<http://www.w3.org/2001/XMLSchema#integer> "0"^^<http://www.w3.org/2001/XMLSchema#integer>
<http://example.com/b> "-0"^^<http://www.w3.org/2001/XMLSchema#integer> "0"^^<http://www.w3.org/2001/XMLSchema#integer>
<http://example.com/c> "+0"^^<http://www.w3.org/2001/XMLSchema#integer> "0"^^<http://www.w3.org/2001/XMLSchema#integer>
<http://example.com/d> "1234"^^<http://www.w3.org/2001/XMLSchema#integer> "1234"^^<http://www.w3.org/2001/XMLSchema#integer>
<http://example.com/e> "-1234"^^<http://www.w3.org/2001/XMLSchema#integer> "1234"^^<http://www.w3.org/2001/XMLSchema#integer>
<http://example.com/f> "+1234"^^<http://www.w3.org/2001/XMLSchema#integer> "1234"^^<http://www.w3.org/2001/XMLSchema#integer>
<http://example.com/g> "1234567890123456789"^^<http://www.w3.org/2001/XMLSchema#integer> "1234567890123456789"^^<http://www.w3.org/2001/XMLSchema#integer>
<http://example.com/h> "-1234567890123456789"^^<http://www.w3.org/2001/XMLSchema#integer> "1234567890123456789"^^<http://www.w3.org/2001/XMLSchema#integer>
<http://example.com/i> "+1234567890123456789"^^<http://www.w3.org/2001/XMLSchema#integer> "1234567890123456789"^^<http://www.w3.org/2001/XMLSchema#integer>
<http://example.com/j> "1234567890.23239300"^^<http://www.w3.org/2001/XMLSchema#decimal> "1234567890.232393"^^<http://www.w3.org/2001/XMLSchema#decimal>
<http://example.com/k> "-1234567890.23239300"^^<http://www.w3.org/2001/XMLSchema#decimal> "1234567890.232393"^^<http://www.w3.org/2001/XMLSchema#decimal>
<http://example.com/l> "+1234567890.23239300"^^<http://www.w3.org/2001/XMLSchema#decimal> "1234567890.232393"^^<http://www.w3.org/2001/XMLSchema#decimal>
<http://example.com/m> "23.0e999999999999999999999999"^^<http://www.w3.org/2001/XMLSchema#float> "inf"^^<http://www.w3.org/2001/XMLSchema#float>
<http://example.com/n> "+23.0e999999999999999999999999"^^<http://www.w3.org/2001/XMLSchema#float> "inf"^^<http://www.w3.org/2001/XMLSchema#float>
<http://example.com/o> "-23.0e999999999999999999999999"^^<http://www.w3.org/2001/XMLSchema#float> "inf"^^<http://www.w3.org/2001/XMLSchema#float>
<http://example.com/p> "12345678901234567890.23239300"^^<http://www.w3.org/2001/XMLSchema#float> "1.23457e+19"^^<http://www.w3.org/2001/XMLSchema#float>
<http://example.com/q> "-12345678901234567890.23239300"^^<http://www.w3.org/2001/XMLSchema#float> "1.23457e+19"^^<http://www.w3.org/2001/XMLSchema#float>
<http://example.com/r> "+12345678901234567890.23239300"^^<http://www.w3.org/2001/XMLSchema#float> "1.23457e+19"^^<http://www.w3.org/2001/XMLSchema#float>
<http://example.com/s> "2.4999"^^<http://www.w3.org/2001/XMLSchema#decimal> "2.4999"^^<http://www.w3.org/2001/XMLSchema#decimal>
<http://example.com/t> "2.5"^^<http://www.w3.org/2001/XMLSchema#decimal> "2.5"^^<http://www.w3.org/2001/XMLSchema#decimal>
<http://example.com/u> "-2.5"^^<http://www.w3.org/2001/XMLSchema#decimal> "2.5"^^<http://www.w3.org/2001/XMLSchema#decimal>
<http://example.com/v> "-2.500001"^^<http://www.w3.org/2001/XMLSchema#decimal> "2.500001"^^<http://www.w3.org/2001/XMLSchema#decimal>
<http://example.com/w> "2.500001"^^<http://www.w3.org/2001/XMLSchema#decimal> "2.500001"^^<http://www.w3.org/2001/XMLSchema#decimal>
<http://example.com/x> "-2.499999"^^<http://www.w3.org/2001/XMLSchema#decimal> "2.499999"^^<http://www.w3.org/2001/XMLSchema#decimal>
<http://example.com/y> "0000.0004999000"^^<http://www.w3.org/2001/XMLSchema#decimal> "0.0004999"^^<http://www.w3.org/2001/XMLSchema#decimal>
<http://example.com/z> "2.000050000"^^<http://www.w3.org/2001/XMLSchema#decimal> "2.00005"^^<http://www.w3.org/2001/XMLSchema#decimal>
<http://example.com/za> "-2.00050000"^^<http://www.w3.org/2001/XMLSchema#decimal> "2.0005"^^<http://www.w3.org/2001/XMLSchema#decimal>
<http://example.com/zb> "2.4999"^^<http://www.w3.org/2001/XMLSchema#float> "2.4999"^^<http://www.w3.org/2001/XMLSchema#float>
<http://example.com/zc> "2.5"^^<http://www.w3.org/2001/XMLSchema#float> "2.5"^^<http://www.w3.org/2001/XMLSchema#float>
<http://example.com/zd> "-2.5"^^<http://www.w3.org/2001/XMLSchema#float> "2.5"^^<http://www.w3.org/2001/XMLSchema#float>
<http://example.com/ze> "-2.500001"^^<http://www.w3.org/2001/XMLSchema#float> "2.5"^^<http://www.w3.org/2001/XMLSchema#float>
<http://example.com/zf> "2.500001"^^<http://www.w3.org/2001/XMLSchema#float> "2.5"^^<http://www.w3.org/2001/XMLSchema#float>
<http://example.com/zg> "-2.499999"^^<http://www.w3.org/2001/XMLSchema#float> "2.5"^^<http://www.w3.org/2001/XMLSchema#float>
<http://example.com/zh> "2.4999"^^<http://www.w3.org/2001/XMLSchema#double> "2.4999"^^<http://www.w3.org/2001/XMLSchema#double>
<http://example.com/zi> "2.5"^^<http://www.w3.org/2001/XMLSchema#double> "2.5"^^<http://www.w3.org/2001/XMLSchema#double>
<http://example.com/zj> "-2.5"^^<http://www.w3.org/2001/XMLSchema#double> "2.5"^^<http://www.w3.org/2001/XMLSchema#double>
<http://example.com/zk> "-2.500001"^^<http://www.w3.org/2001/XMLSchema#double> "2.5"^^<http://www.w3.org/2001/XMLSchema#double>
<http://example.com/zl> "2.500001"^^<http://www.w3.org/2001/XMLSchema#double> "2.5"^^<http://www.w3.org/2001/XMLSchema#double>
<http://example.com/zm> "-2.499999"^^<http://www.w3.org/2001/XMLSchema#double> "2.5"^^<http://www.w3.org/2001/XMLSchema#double>
200 deleted successfully
This is a 4store SPARQL server [VERSION]

0 comments on commit d35139a

Please sign in to comment.