summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2019-07-07 22:50:00 +0200
committerCarlos Garnacho <carlosg@gnome.org>2019-09-10 00:22:58 +0200
commit3cc070c50bb17df0d8bcb7b4e156ba959d0f83b4 (patch)
treefddcc916bdb41ee63c89cf2fc48c0f0231f63c0b /src
parentdf87b58d25296360895ca68a58d85f0b44942f47 (diff)
downloadtracker-3cc070c50bb17df0d8bcb7b4e156ba959d0f83b4.tar.gz
libtracker-data: Add support for CONSTRUCT
Diffstat (limited to 'src')
-rw-r--r--src/libtracker-data/tracker-sparql.c181
1 files changed, 176 insertions, 5 deletions
diff --git a/src/libtracker-data/tracker-sparql.c b/src/libtracker-data/tracker-sparql.c
index d3c50a449..2f8895742 100644
--- a/src/libtracker-data/tracker-sparql.c
+++ b/src/libtracker-data/tracker-sparql.c
@@ -73,6 +73,8 @@ static TrackerDBStatement * prepare_query (TrackerDBInterface *iface,
GError **error);
static inline TrackerVariable * _ensure_variable (TrackerSparql *sparql,
const gchar *name);
+static void convert_expression_to_string (TrackerSparql *sparql,
+ TrackerPropertyType type);
#define _raise(v,s,sub) \
G_STMT_START { \
@@ -102,6 +104,7 @@ enum
TRACKER_SPARQL_TYPE_DELETE,
TRACKER_SPARQL_TYPE_INSERT,
TRACKER_SPARQL_TYPE_UPDATE,
+ TRACKER_SPARQL_TYPE_CONSTRUCT,
};
struct _TrackerSparql
@@ -140,6 +143,7 @@ struct _TrackerSparql
TrackerContext *select_context;
TrackerStringBuilder *sql;
TrackerStringBuilder *with_clauses;
+ TrackerStringBuilder *construct_query;
TrackerParserNode *node;
TrackerParserNode *prev_node;
@@ -189,6 +193,8 @@ tracker_sparql_finalize (GObject *object)
tracker_token_unset (&sparql->current_state.subject);
tracker_token_unset (&sparql->current_state.predicate);
tracker_token_unset (&sparql->current_state.object);
+ g_clear_pointer (&sparql->current_state.construct_query,
+ tracker_string_builder_free);
g_clear_object (&sparql->current_state.as_in_group_by);
g_ptr_array_unref (sparql->named_graphs);
@@ -923,7 +929,8 @@ _init_token (TrackerToken *token,
if (tracker_grammar_rule_is_a (rule, RULE_TYPE_TERMINAL, TERMINAL_TYPE_VAR1) ||
tracker_grammar_rule_is_a (rule, RULE_TYPE_TERMINAL, TERMINAL_TYPE_VAR2)) {
- if (sparql->current_state.type == TRACKER_SPARQL_TYPE_SELECT) {
+ if (sparql->current_state.type == TRACKER_SPARQL_TYPE_SELECT ||
+ sparql->current_state.type == TRACKER_SPARQL_TYPE_CONSTRUCT) {
var = _ensure_variable (sparql, str);
tracker_token_variable_init (token, var);
} else {
@@ -1464,6 +1471,99 @@ _add_quad (TrackerSparql *sparql,
return TRUE;
}
+static void
+add_construct_variable (TrackerSparql *sparql,
+ TrackerVariable *var)
+{
+ TrackerPropertyType prop_type;
+ TrackerStringBuilder *str, *old;
+
+ str = _append_placeholder (sparql);
+ old = tracker_sparql_swap_builder (sparql, str);
+
+ _append_variable_sql (sparql, var);
+
+ prop_type = TRACKER_BINDING (tracker_variable_get_sample_binding (var))->data_type;
+ convert_expression_to_string (sparql, prop_type);
+
+ tracker_sparql_swap_builder (sparql, old);
+}
+
+static gboolean
+_construct_clause (TrackerSparql *sparql,
+ TrackerToken *graph,
+ TrackerToken *subject,
+ TrackerToken *predicate,
+ TrackerToken *object,
+ GError **error)
+{
+ gchar *construct_query;
+
+ if (!tracker_string_builder_is_empty (sparql->current_state.sql))
+ _append_string (sparql, "UNION ALL ");
+
+ _append_string (sparql, "SELECT ");
+
+ if (tracker_token_get_variable (subject) &&
+ tracker_variable_get_sample_binding (tracker_token_get_variable (subject)))
+ add_construct_variable (sparql, tracker_token_get_variable (subject));
+ else
+ _append_string_printf (sparql, "\"%s\" ", tracker_token_get_idstring (subject));
+
+ _append_string (sparql, "AS subject, ");
+
+ if (tracker_token_get_variable (predicate) &&
+ tracker_variable_get_sample_binding (tracker_token_get_variable (predicate)))
+ add_construct_variable (sparql, tracker_token_get_variable (predicate));
+ else
+ _append_string_printf (sparql, "\"%s\" ", tracker_token_get_idstring (predicate));
+
+ _append_string (sparql, "AS predicate, ");
+
+ if (tracker_token_get_variable (object) &&
+ tracker_variable_get_sample_binding (tracker_token_get_variable (object)))
+ add_construct_variable (sparql, tracker_token_get_variable (object));
+ else
+ _append_string_printf (sparql, "\"%s\" ", tracker_token_get_idstring (object));
+
+ _append_string (sparql, "AS object ");
+
+ if (tracker_token_get_variable (subject) ||
+ tracker_token_get_variable (predicate) ||
+ tracker_token_get_variable (object)) {
+ gboolean first = TRUE;
+ _append_string (sparql, "FROM (SELECT DISTINCT ");
+
+ if (tracker_token_get_variable (subject)) {
+ _append_variable_sql (sparql, tracker_token_get_variable (subject));
+ first = FALSE;
+ }
+
+ if (tracker_token_get_variable (predicate)) {
+ if (!first)
+ _append_string (sparql, ", ");
+ _append_variable_sql (sparql, tracker_token_get_variable (predicate));
+ first = FALSE;
+ }
+
+ if (tracker_token_get_variable (object)) {
+ if (!first)
+ _append_string (sparql, ", ");
+ _append_variable_sql (sparql, tracker_token_get_variable (object));
+ }
+
+ _append_string (sparql, " FROM (");
+
+ construct_query = tracker_string_builder_to_string (sparql->current_state.construct_query);
+ _append_string_printf (sparql, "%s", construct_query);
+ g_free (construct_query);
+
+ _append_string (sparql, ")) ");
+ }
+
+ return TRUE;
+}
+
static gboolean
tracker_sparql_apply_quad (TrackerSparql *sparql,
GError **error)
@@ -1479,6 +1579,14 @@ tracker_sparql_apply_quad (TrackerSparql *sparql,
&sparql->current_state.object,
&inner_error);
break;
+ case TRACKER_SPARQL_TYPE_CONSTRUCT:
+ _construct_clause (sparql,
+ &sparql->current_state.graph,
+ &sparql->current_state.subject,
+ &sparql->current_state.predicate,
+ &sparql->current_state.object,
+ &inner_error);
+ break;
case TRACKER_SPARQL_TYPE_INSERT:
tracker_data_insert_statement (tracker_data_manager_get_data (sparql->data_manager),
tracker_token_get_idstring (&sparql->current_state.graph),
@@ -2242,7 +2350,66 @@ static gboolean
translate_ConstructQuery (TrackerSparql *sparql,
GError **error)
{
- _unimplemented ("CONSTRUCT");
+ TrackerParserNode *node = NULL;
+ TrackerStringBuilder *old;
+
+ /* ConstructQuery ::= 'CONSTRUCT' ( ConstructTemplate DatasetClause* WhereClause SolutionModifier |
+ * DatasetClause* 'WHERE' '{' TriplesTemplate? '}' SolutionModifier )
+ */
+ _expect (sparql, RULE_TYPE_LITERAL, LITERAL_CONSTRUCT);
+ sparql->current_state.construct_query = tracker_string_builder_new ();
+
+ if (_current_rule (sparql) == NAMED_RULE_ConstructTemplate) {
+ node = _skip_rule (sparql, NAMED_RULE_ConstructTemplate);
+
+ old = tracker_sparql_swap_builder (sparql, sparql->current_state.construct_query);
+
+ _append_string (sparql, "SELECT * ");
+
+ while (_current_rule (sparql) == NAMED_RULE_DatasetClause)
+ _call_rule (sparql, NAMED_RULE_DatasetClause, error);
+
+ _call_rule (sparql, NAMED_RULE_WhereClause, error);
+ _call_rule (sparql, NAMED_RULE_SolutionModifier, error);
+ tracker_sparql_swap_builder (sparql, old);
+
+ sparql->current_state.type = TRACKER_SPARQL_TYPE_CONSTRUCT;
+ if (!_postprocess_rule (sparql, node, NULL, error))
+ return FALSE;
+ } else {
+ while (_current_rule (sparql) == NAMED_RULE_DatasetClause)
+ _call_rule (sparql, NAMED_RULE_DatasetClause, error);
+
+ _expect (sparql, RULE_TYPE_LITERAL, LITERAL_WHERE);
+ _expect (sparql, RULE_TYPE_LITERAL, LITERAL_OPEN_BRACE);
+
+ if (_current_rule (sparql) == NAMED_RULE_TriplesTemplate) {
+ node = _skip_rule (sparql, NAMED_RULE_TriplesTemplate);
+
+ old = tracker_sparql_swap_builder (sparql, sparql->current_state.construct_query);
+
+ _begin_triples_block (sparql);
+ if (!_postprocess_rule (sparql, node, NULL, error))
+ return FALSE;
+ if (!_end_triples_block (sparql, error))
+ return FALSE;
+
+ _expect (sparql, RULE_TYPE_LITERAL, LITERAL_CLOSE_BRACE);
+ _call_rule (sparql, NAMED_RULE_SolutionModifier, error);
+ tracker_sparql_swap_builder (sparql, old);
+
+ /* Switch to construct mode, and rerun again the triples template */
+ sparql->current_state.type = TRACKER_SPARQL_TYPE_CONSTRUCT;
+ if (!_postprocess_rule (sparql, node, NULL, error))
+ return FALSE;
+ } else {
+ _append_string (sparql, "SELECT NULL ");
+ _expect (sparql, RULE_TYPE_LITERAL, LITERAL_CLOSE_BRACE);
+ _call_rule (sparql, NAMED_RULE_SolutionModifier, error);
+ }
+ }
+
+ return TRUE;
}
static gboolean
@@ -5818,6 +5985,7 @@ translate_VarOrTerm (TrackerSparql *sparql,
switch (rule) {
case NAMED_RULE_Var:
if (sparql->current_state.type != TRACKER_SPARQL_TYPE_SELECT &&
+ sparql->current_state.type != TRACKER_SPARQL_TYPE_CONSTRUCT &&
!sparql->solution_var_map) {
TrackerParserNode *node = sparql->current_state.node;
const gchar *str = "Unknown";
@@ -5888,7 +6056,8 @@ translate_Var (TrackerSparql *sparql,
if (_accept (sparql, RULE_TYPE_TERMINAL, TERMINAL_TYPE_VAR1) ||
_accept (sparql, RULE_TYPE_TERMINAL, TERMINAL_TYPE_VAR2)) {
- if (sparql->current_state.type == TRACKER_SPARQL_TYPE_SELECT) {
+ if (sparql->current_state.type == TRACKER_SPARQL_TYPE_SELECT ||
+ sparql->current_state.type == TRACKER_SPARQL_TYPE_CONSTRUCT) {
TrackerVariableBinding *binding;
TrackerVariable *var;
@@ -7559,7 +7728,8 @@ translate_RDFLiteral (TrackerSparql *sparql,
tracker_binding_set_data_type (binding, type);
if (!is_parameter &&
- sparql->current_state.type == TRACKER_SPARQL_TYPE_SELECT) {
+ (sparql->current_state.type == TRACKER_SPARQL_TYPE_SELECT ||
+ sparql->current_state.type == TRACKER_SPARQL_TYPE_CONSTRUCT)) {
tracker_select_context_add_literal_binding (TRACKER_SELECT_CONTEXT (sparql->context),
TRACKER_LITERAL_BINDING (binding));
}
@@ -7771,7 +7941,8 @@ translate_BlankNode (TrackerSparql *sparql,
iface = tracker_data_manager_get_writable_db_interface (sparql->data_manager);
- if (sparql->current_state.type != TRACKER_SPARQL_TYPE_SELECT) {
+ if (sparql->current_state.type != TRACKER_SPARQL_TYPE_SELECT &&
+ sparql->current_state.type != TRACKER_SPARQL_TYPE_CONSTRUCT) {
if (_accept (sparql, RULE_TYPE_TERMINAL, TERMINAL_TYPE_ANON)) {
bnode_id = tracker_data_query_unused_uuid (sparql->data_manager, iface);
tracker_token_literal_init (sparql->current_state.token, bnode_id, -1);