diff options
author | Carlos Garnacho <carlosg@gnome.org> | 2021-04-12 01:18:00 +0200 |
---|---|---|
committer | Carlos Garnacho <carlosg@gnome.org> | 2021-04-12 11:06:37 +0200 |
commit | 3d7aede37569eae215046a8311de8879b3b84707 (patch) | |
tree | a78e3abf1b8a56bbaf737832f0bc34968791ef8e | |
parent | 3ffe21d9e0274fe3596f9bc9ae2a0cc6539e7d5d (diff) | |
download | tracker-3d7aede37569eae215046a8311de8879b3b84707.tar.gz |
libtracker-data: Handle relational expressions with arbitrary datetimes
This had some holes, since we can store datetimes in 2 different formats
(unix timestamps and iso8601 datetime strings), but rely on direct comparisons
for all data types inside FILTER().
Detect date/time comparisons, and use the resulting SparqlTimeSort() to
compare the values on both sides of the relational expression, this takes
care of evening out the format and timezone differences so we can compare
all timestamps.
-rw-r--r-- | src/libtracker-data/tracker-sparql.c | 46 |
1 files changed, 45 insertions, 1 deletions
diff --git a/src/libtracker-data/tracker-sparql.c b/src/libtracker-data/tracker-sparql.c index 6d83ae315..cafe87e6b 100644 --- a/src/libtracker-data/tracker-sparql.c +++ b/src/libtracker-data/tracker-sparql.c @@ -151,6 +151,7 @@ typedef struct gboolean convert_to_string; gboolean in_property_function; + gboolean in_relational_expression; } TrackerSparqlState; struct _TrackerSparql @@ -7372,12 +7373,19 @@ static gboolean translate_RelationalExpression (TrackerSparql *sparql, GError **error) { + TrackerStringBuilder *str, *old; const gchar *old_sep; - gboolean bool_op = TRUE; + gboolean in_relational_expression, bool_op = TRUE; /* RelationalExpression ::= NumericExpression ( '=' NumericExpression | '!=' NumericExpression | '<' NumericExpression | '>' NumericExpression | '<=' NumericExpression | '>=' NumericExpression | 'IN' ExpressionList | 'NOT' 'IN' ExpressionList )? */ + str = _append_placeholder (sparql); + old = tracker_sparql_swap_builder (sparql, str); _call_rule (sparql, NAMED_RULE_NumericExpression, error); + tracker_sparql_swap_builder (sparql, old); + + in_relational_expression = sparql->current_state->in_relational_expression; + sparql->current_state->in_relational_expression = TRUE; if (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_OP_IN)) { _append_string (sparql, "IN "); @@ -7410,12 +7418,24 @@ translate_RelationalExpression (TrackerSparql *sparql, _call_rule (sparql, NAMED_RULE_NumericExpression, error); } else { /* This is an unary expression */ + sparql->current_state->in_relational_expression = FALSE; bool_op = FALSE; } + if (sparql->current_state->in_relational_expression && + (sparql->current_state->expression_type == TRACKER_PROPERTY_TYPE_DATE || + sparql->current_state->expression_type == TRACKER_PROPERTY_TYPE_DATETIME)) { + old = tracker_sparql_swap_builder (sparql, str); + _prepend_string (sparql, "SparqlTimeSort("); + _append_string (sparql, ") "); + tracker_sparql_swap_builder (sparql, old); + } + if (bool_op) sparql->current_state->expression_type = TRACKER_PROPERTY_TYPE_BOOLEAN; + sparql->current_state->in_relational_expression = in_relational_expression; + return TRUE; } @@ -7555,6 +7575,8 @@ translate_PrimaryExpression (TrackerSparql *sparql, TrackerGrammarNamedRule rule; TrackerBinding *binding; TrackerVariable *variable; + TrackerStringBuilder *str, *old; + gboolean is_datetime_comparison = FALSE; gchar *name; /* PrimaryExpression ::= BrackettedExpression | BuiltInCall | iriOrFunction | RDFLiteral | NumericLiteral | BooleanLiteral | Var @@ -7562,6 +7584,9 @@ translate_PrimaryExpression (TrackerSparql *sparql, rule = _current_rule (sparql); select_context = TRACKER_SELECT_CONTEXT (sparql->context); + str = _append_placeholder (sparql); + old = tracker_sparql_swap_builder (sparql, str); + switch (rule) { case NAMED_RULE_NumericLiteral: case NAMED_RULE_BooleanLiteral: @@ -7576,6 +7601,11 @@ translate_PrimaryExpression (TrackerSparql *sparql, _call_rule (sparql, rule, error); name = _dup_last_string (sparql); + is_datetime_comparison = + (sparql->current_state->in_relational_expression && + (sparql->current_state->expression_type == TRACKER_PROPERTY_TYPE_DATE || + sparql->current_state->expression_type == TRACKER_PROPERTY_TYPE_DATETIME)); + if (tracker_context_lookup_variable_by_name (sparql->current_state->context, name)) { variable = _last_node_variable (sparql); @@ -7596,6 +7626,13 @@ translate_PrimaryExpression (TrackerSparql *sparql, _call_rule (sparql, rule, error); binding = g_ptr_array_index (select_context->literal_bindings, select_context->literal_bindings->len - 1); + sparql->current_state->expression_type = binding->data_type; + + is_datetime_comparison = + (sparql->current_state->in_relational_expression && + (binding->data_type == TRACKER_PROPERTY_TYPE_DATE || + binding->data_type == TRACKER_PROPERTY_TYPE_DATETIME)); + _append_literal_sql (sparql, TRACKER_LITERAL_BINDING (binding)); break; case NAMED_RULE_BrackettedExpression: @@ -7607,6 +7644,13 @@ translate_PrimaryExpression (TrackerSparql *sparql, g_assert_not_reached (); } + if (is_datetime_comparison) { + _prepend_string (sparql, "SparqlTimeSort("); + _append_string (sparql, ") "); + } + + tracker_sparql_swap_builder (sparql, old); + return TRUE; } |