[tracker/wip/carlosg/datetime-comparisons: 58/61] libtracker-data: Handle relational expressions with arbitrary datetimes




commit 3ea5f9e8e38ee7d872fe9df7a2c54cefdb99ca7b
Author: Carlos Garnacho <carlosg gnome org>
Date:   Mon Apr 12 01:18:00 2021 +0200

    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.

 src/libtracker-data/tracker-sparql.c | 46 +++++++++++++++++++++++++++++++++++-
 1 file changed, 45 insertions(+), 1 deletion(-)
---
diff --git a/src/libtracker-data/tracker-sparql.c b/src/libtracker-data/tracker-sparql.c
index 522486b7b..89e9f0b27 100644
--- a/src/libtracker-data/tracker-sparql.c
+++ b/src/libtracker-data/tracker-sparql.c
@@ -153,6 +153,7 @@ typedef struct
 
        gboolean convert_to_string;
        gboolean in_property_function;
+       gboolean in_relational_expression;
 } TrackerSparqlState;
 
 struct _TrackerSparql
@@ -7414,12 +7415,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 ");
@@ -7452,12 +7460,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;
 }
 
@@ -7597,6 +7617,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
@@ -7604,6 +7626,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:
@@ -7618,6 +7643,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);
@@ -7638,6 +7668,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:
@@ -7649,6 +7686,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;
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]