|
Packit Service |
a3c5fa |
/*
|
|
Packit Service |
a3c5fa |
* Copyright (C) 2018 Richard Hughes <richard@hughsie.com>
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* SPDX-License-Identifier: LGPL-2.1+
|
|
Packit Service |
a3c5fa |
*/
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
#define G_LOG_DOMAIN "XbSilo"
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
#include "config.h"
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
#include <string.h>
|
|
Packit Service |
a3c5fa |
#include <gio/gio.h>
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
#include "xb-node-private.h"
|
|
Packit Service |
a3c5fa |
#include "xb-opcode.h"
|
|
Packit Service |
a3c5fa |
#include "xb-silo-private.h"
|
|
Packit Service |
a3c5fa |
#include "xb-silo-query-private.h"
|
|
Packit Service |
a3c5fa |
#include "xb-stack-private.h"
|
|
Packit Service |
a3c5fa |
#include "xb-query-private.h"
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
static gboolean
|
|
Packit Service |
a3c5fa |
xb_silo_query_node_matches (XbSilo *self,
|
|
Packit Service |
a3c5fa |
XbMachine *machine,
|
|
Packit Service |
a3c5fa |
XbSiloNode *sn,
|
|
Packit Service |
a3c5fa |
XbQuerySection *section,
|
|
Packit Service |
a3c5fa |
XbSiloQueryData *query_data,
|
|
Packit Service |
a3c5fa |
gboolean *result,
|
|
Packit Service |
a3c5fa |
GError **error)
|
|
Packit Service |
a3c5fa |
{
|
|
Packit Service |
a3c5fa |
/* we have an index into the string table */
|
|
Packit Service |
a3c5fa |
if (section->element_idx != sn->element_name &&
|
|
Packit Service |
a3c5fa |
section->kind != XB_SILO_QUERY_KIND_WILDCARD) {
|
|
Packit Service |
a3c5fa |
*result = FALSE;
|
|
Packit Service |
a3c5fa |
return TRUE;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* for section */
|
|
Packit Service |
a3c5fa |
query_data->position += 1;
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* check predicates */
|
|
Packit Service |
a3c5fa |
if (section->predicates != NULL) {
|
|
Packit Service |
a3c5fa |
for (guint i = 0; i < section->predicates->len; i++) {
|
|
Packit Service |
a3c5fa |
XbStack *opcodes = g_ptr_array_index (section->predicates, i);
|
|
Packit Service |
a3c5fa |
if (!xb_machine_run (machine, opcodes, result, query_data, error))
|
|
Packit Service |
a3c5fa |
return FALSE;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* success */
|
|
Packit Service |
a3c5fa |
return TRUE;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
typedef struct {
|
|
Packit Service |
a3c5fa |
GPtrArray *sections; /* of XbQuerySection */
|
|
Packit Service |
a3c5fa |
GPtrArray *results; /* of XbNode */
|
|
Packit Service |
a3c5fa |
GHashTable *results_hash; /* of sn:1 */
|
|
Packit Service |
a3c5fa |
guint limit;
|
|
Packit Service |
a3c5fa |
XbSiloQueryData *query_data;
|
|
Packit Service |
a3c5fa |
} XbSiloQueryHelper;
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
static gboolean
|
|
Packit Service |
a3c5fa |
xb_silo_query_section_add_result (XbSilo *self, XbSiloQueryHelper *helper, XbSiloNode *sn)
|
|
Packit Service |
a3c5fa |
{
|
|
Packit Service |
a3c5fa |
if (g_hash_table_lookup (helper->results_hash, sn) != NULL)
|
|
Packit Service |
a3c5fa |
return FALSE;
|
|
Packit Service |
a3c5fa |
g_ptr_array_add (helper->results, xb_silo_node_create (self, sn));
|
|
Packit Service |
a3c5fa |
g_hash_table_add (helper->results_hash, sn);
|
|
Packit Service |
a3c5fa |
return helper->results->len == helper->limit;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/*
|
|
Packit Service |
a3c5fa |
* @parent: (allow-none)
|
|
Packit Service |
a3c5fa |
*/
|
|
Packit Service |
a3c5fa |
static gboolean
|
|
Packit Service |
a3c5fa |
xb_silo_query_section_root (XbSilo *self,
|
|
Packit Service |
a3c5fa |
XbSiloNode *sn,
|
|
Packit Service |
a3c5fa |
guint i,
|
|
Packit Service |
a3c5fa |
XbSiloQueryHelper *helper,
|
|
Packit Service |
a3c5fa |
GError **error)
|
|
Packit Service |
a3c5fa |
{
|
|
Packit Service |
a3c5fa |
XbMachine *machine = xb_silo_get_machine (self);
|
|
Packit Service |
a3c5fa |
XbSiloQueryData *query_data = helper->query_data;
|
|
Packit Service |
a3c5fa |
XbQuerySection *section = g_ptr_array_index (helper->sections, i);
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* handle parent */
|
|
Packit Service |
a3c5fa |
if (section->kind == XB_SILO_QUERY_KIND_PARENT) {
|
|
Packit Service |
a3c5fa |
XbSiloNode *parent;
|
|
Packit Service |
a3c5fa |
if (sn == NULL) {
|
|
Packit Service |
a3c5fa |
g_set_error_literal (error,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR_INVALID_ARGUMENT,
|
|
Packit Service |
a3c5fa |
"cannot obtain parent for root");
|
|
Packit Service |
a3c5fa |
return FALSE;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
parent = xb_silo_node_get_parent (self, sn);
|
|
Packit Service |
a3c5fa |
if (parent == NULL) {
|
|
Packit Service |
a3c5fa |
g_set_error (error,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR_INVALID_ARGUMENT,
|
|
Packit Service |
a3c5fa |
"no parent set for %s",
|
|
Packit Service |
a3c5fa |
xb_silo_node_get_element (self, sn));
|
|
Packit Service |
a3c5fa |
return FALSE;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
if (i == helper->sections->len - 1) {
|
|
Packit Service |
a3c5fa |
xb_silo_query_section_add_result (self, helper, parent);
|
|
Packit Service |
a3c5fa |
return TRUE;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
// g_debug ("PARENT @%u",
|
|
Packit Service |
a3c5fa |
// xb_silo_get_offset_for_node (self, parent));
|
|
Packit Service |
a3c5fa |
return xb_silo_query_section_root (self, parent, i + 1, helper, error);
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* no node means root */
|
|
Packit Service |
a3c5fa |
if (sn == NULL) {
|
|
Packit Service |
a3c5fa |
sn = xb_silo_get_sroot (self);
|
|
Packit Service |
a3c5fa |
if (sn == NULL) {
|
|
Packit Service |
a3c5fa |
g_set_error_literal (error,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR_NOT_FOUND,
|
|
Packit Service |
a3c5fa |
"silo root not found");
|
|
Packit Service |
a3c5fa |
return FALSE;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
} else {
|
|
Packit Service |
a3c5fa |
sn = xb_silo_node_get_child (self, sn);
|
|
Packit Service |
a3c5fa |
if (sn == NULL)
|
|
Packit Service |
a3c5fa |
return TRUE;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* set up level pointer */
|
|
Packit Service |
a3c5fa |
query_data->position = 0;
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* continue matching children ".." */
|
|
Packit Service |
a3c5fa |
do {
|
|
Packit Service |
a3c5fa |
gboolean result = TRUE;
|
|
Packit Service |
a3c5fa |
query_data->sn = sn;
|
|
Packit Service |
a3c5fa |
if (!xb_silo_query_node_matches (self, machine, sn, section,
|
|
Packit Service |
a3c5fa |
query_data, &result, error))
|
|
Packit Service |
a3c5fa |
return FALSE;
|
|
Packit Service |
a3c5fa |
if (result) {
|
|
Packit Service |
a3c5fa |
if (i == helper->sections->len - 1) {
|
|
Packit Service |
a3c5fa |
// g_debug ("add result %u",
|
|
Packit Service |
a3c5fa |
// xb_silo_get_offset_for_node (self, sn));
|
|
Packit Service |
a3c5fa |
if (xb_silo_query_section_add_result (self, helper, sn))
|
|
Packit Service |
a3c5fa |
break;
|
|
Packit Service |
a3c5fa |
} else {
|
|
Packit Service |
a3c5fa |
// g_debug ("MATCH %s at @%u, deeper",
|
|
Packit Service |
a3c5fa |
// xb_silo_node_get_element (self, sn),
|
|
Packit Service |
a3c5fa |
// xb_silo_get_offset_for_node (self, sn));
|
|
Packit Service |
a3c5fa |
if (!xb_silo_query_section_root (self, sn, i + 1, helper, error))
|
|
Packit Service |
a3c5fa |
return FALSE;
|
|
Packit Service |
a3c5fa |
if (helper->results->len > 0 &&
|
|
Packit Service |
a3c5fa |
helper->results->len == helper->limit)
|
|
Packit Service |
a3c5fa |
break;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
if (sn->next == 0x0)
|
|
Packit Service |
a3c5fa |
break;
|
|
Packit Service |
a3c5fa |
sn = xb_silo_get_node (self, sn->next);
|
|
Packit Service |
a3c5fa |
} while (TRUE);
|
|
Packit Service |
a3c5fa |
return TRUE;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
static gboolean
|
|
Packit Service |
a3c5fa |
xb_silo_query_part (XbSilo *self,
|
|
Packit Service |
a3c5fa |
XbSiloNode *sroot,
|
|
Packit Service |
a3c5fa |
GPtrArray *results,
|
|
Packit Service |
a3c5fa |
GHashTable *results_hash,
|
|
Packit Service |
a3c5fa |
XbQuery *query,
|
|
Packit Service |
a3c5fa |
XbSiloQueryData *query_data,
|
|
Packit Service |
a3c5fa |
GError **error)
|
|
Packit Service |
a3c5fa |
{
|
|
Packit Service |
a3c5fa |
XbSiloQueryHelper helper = {
|
|
Packit Service |
a3c5fa |
.results = results,
|
|
Packit Service |
a3c5fa |
.limit = xb_query_get_limit (query),
|
|
Packit Service |
a3c5fa |
.results_hash = results_hash,
|
|
Packit Service |
a3c5fa |
.query_data = query_data,
|
|
Packit Service |
a3c5fa |
};
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* find each section */
|
|
Packit Service |
a3c5fa |
helper.sections = xb_query_get_sections (query);
|
|
Packit Service |
a3c5fa |
return xb_silo_query_section_root (self, sroot, 0, &helper, error);
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/**
|
|
Packit Service |
a3c5fa |
* xb_silo_query_with_root: (skip)
|
|
Packit Service |
a3c5fa |
* @self: a #XbSilo
|
|
Packit Service |
a3c5fa |
* @n: (allow-none): a #XbNode
|
|
Packit Service |
a3c5fa |
* @xpath: an XPath, e.g. `/components/component[@type=desktop]/id[abe.desktop]`
|
|
Packit Service |
a3c5fa |
* @limit: maximum number of results to return, or 0 for "all"
|
|
Packit Service |
a3c5fa |
* @error: the #GError, or %NULL
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Searches the silo using an XPath query, returning up to @limit results.
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* It is safe to call this function from a different thread to the one that
|
|
Packit Service |
a3c5fa |
* created the #XbSilo.
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Please note: Only a subset of XPath is supported.
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Returns: (transfer container) (element-type XbNode): results, or %NULL if unfound
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Since: 0.1.0
|
|
Packit Service |
a3c5fa |
**/
|
|
Packit Service |
a3c5fa |
GPtrArray *
|
|
Packit Service |
a3c5fa |
xb_silo_query_with_root (XbSilo *self, XbNode *n, const gchar *xpath, guint limit, GError **error)
|
|
Packit Service |
a3c5fa |
{
|
|
Packit Service |
a3c5fa |
XbSiloNode *sn = NULL;
|
|
Packit Service |
a3c5fa |
g_auto(GStrv) split = NULL;
|
|
Packit Service |
a3c5fa |
g_autoptr(GHashTable) results_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
|
|
Packit Service |
a3c5fa |
g_autoptr(GPtrArray) results = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
|
|
Packit Service |
a3c5fa |
g_autoptr(GTimer) timer = g_timer_new ();
|
|
Packit Service |
a3c5fa |
XbSiloQueryData query_data = {
|
|
Packit Service |
a3c5fa |
.sn = NULL,
|
|
Packit Service |
a3c5fa |
.position = 0,
|
|
Packit Service |
a3c5fa |
};
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
g_return_val_if_fail (XB_IS_SILO (self), NULL);
|
|
Packit Service |
a3c5fa |
g_return_val_if_fail (xpath != NULL, NULL);
|
|
Packit Service |
a3c5fa |
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* empty silo */
|
|
Packit Service |
a3c5fa |
if (xb_silo_is_empty (self)) {
|
|
Packit Service |
a3c5fa |
g_set_error_literal (error,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR_NOT_FOUND,
|
|
Packit Service |
a3c5fa |
"silo has no data");
|
|
Packit Service |
a3c5fa |
return NULL;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* subtree query */
|
|
Packit Service |
a3c5fa |
if (n != NULL) {
|
|
Packit Service |
a3c5fa |
sn = xb_node_get_sn (n);
|
|
Packit Service |
a3c5fa |
if (xpath[0] == '/') {
|
|
Packit Service |
a3c5fa |
g_set_error_literal (error,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR_NOT_SUPPORTED,
|
|
Packit Service |
a3c5fa |
"XPath node query not supported");
|
|
Packit Service |
a3c5fa |
return NULL;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
} else {
|
|
Packit Service |
a3c5fa |
/* assume it's just a root query */
|
|
Packit Service |
a3c5fa |
if (xpath[0] == '/')
|
|
Packit Service |
a3c5fa |
xpath++;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* do 'or' searches */
|
|
Packit Service |
a3c5fa |
split = g_strsplit (xpath, "|", -1);
|
|
Packit Service |
a3c5fa |
for (guint i = 0; split[i] != NULL; i++) {
|
|
Packit Service |
a3c5fa |
g_autoptr(GError) error_local = NULL;
|
|
Packit Service |
a3c5fa |
g_autoptr(XbQuery) query = xb_query_new (self, split[i], &error_local);
|
|
Packit Service |
a3c5fa |
if (query == NULL) {
|
|
Packit Service |
a3c5fa |
if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT) &&
|
|
Packit Service |
a3c5fa |
(split[i + 1] != NULL || results->len > 0)) {
|
|
Packit Service |
a3c5fa |
g_debug ("ignoring for OR statement: %s",
|
|
Packit Service |
a3c5fa |
error_local->message);
|
|
Packit Service |
a3c5fa |
continue;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
g_propagate_prefixed_error (error,
|
|
Packit Service |
a3c5fa |
g_steal_pointer (&error_local),
|
|
Packit Service |
a3c5fa |
"failed to process %s: ",
|
|
Packit Service |
a3c5fa |
xpath);
|
|
Packit Service |
a3c5fa |
return NULL;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
xb_query_set_limit (query, limit);
|
|
Packit Service |
a3c5fa |
if (!xb_silo_query_part (self, sn,
|
|
Packit Service |
a3c5fa |
results, results_hash,
|
|
Packit Service |
a3c5fa |
query, &query_data,
|
|
Packit Service |
a3c5fa |
error)) {
|
|
Packit Service |
a3c5fa |
return NULL;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* profile */
|
|
Packit Service |
a3c5fa |
if (xb_silo_get_profile_flags (self) & XB_SILO_PROFILE_FLAG_XPATH) {
|
|
Packit Service |
a3c5fa |
xb_silo_add_profile (self, timer,
|
|
Packit Service |
a3c5fa |
"query on %s with `%s` limit=%u -> %u results",
|
|
Packit Service |
a3c5fa |
n != NULL ? xb_node_get_element (n) : "/",
|
|
Packit Service |
a3c5fa |
xpath, limit, results->len);
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* nothing found */
|
|
Packit Service |
a3c5fa |
if (results->len == 0) {
|
|
Packit Service |
a3c5fa |
g_set_error (error,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR_NOT_FOUND,
|
|
Packit Service |
a3c5fa |
"no results for XPath query '%s'",
|
|
Packit Service |
a3c5fa |
xpath);
|
|
Packit Service |
a3c5fa |
return NULL;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
return g_steal_pointer (&results);
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
static void
|
|
Packit Service |
a3c5fa |
_g_ptr_array_reverse (GPtrArray *array)
|
|
Packit Service |
a3c5fa |
{
|
|
Packit Service |
a3c5fa |
guint last_idx = array->len - 1;
|
|
Packit Service |
a3c5fa |
for (guint i = 0; i < array->len / 2; i++) {
|
|
Packit Service |
a3c5fa |
gpointer tmp = array->pdata[i];
|
|
Packit Service |
a3c5fa |
array->pdata[i] = array->pdata[last_idx - i];
|
|
Packit Service |
a3c5fa |
array->pdata[last_idx - i] = tmp;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/**
|
|
Packit Service |
a3c5fa |
* xb_silo_query_with_root_full: (skip)
|
|
Packit Service |
a3c5fa |
* @self: a #XbSilo
|
|
Packit Service |
a3c5fa |
* @n: (allow-none): a #XbNode
|
|
Packit Service |
a3c5fa |
* @query: an #XbQuery
|
|
Packit Service |
a3c5fa |
* @error: the #GError, or %NULL
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Searches the silo using an XPath query, returning up to @limit results.
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* It is safe to call this function from a different thread to the one that
|
|
Packit Service |
a3c5fa |
* created the #XbSilo.
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Please note: Only a subset of XPath is supported.
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Returns: (transfer container) (element-type XbNode): results, or %NULL if unfound
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Since: 0.1.4
|
|
Packit Service |
a3c5fa |
**/
|
|
Packit Service |
a3c5fa |
GPtrArray *
|
|
Packit Service |
a3c5fa |
xb_silo_query_with_root_full (XbSilo *self, XbNode *n, XbQuery *query, GError **error)
|
|
Packit Service |
a3c5fa |
{
|
|
Packit Service |
a3c5fa |
XbSiloNode *sn = NULL;
|
|
Packit Service |
a3c5fa |
g_autoptr(GHashTable) results_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
|
|
Packit Service |
a3c5fa |
g_autoptr(GPtrArray) results = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
|
|
Packit Service |
a3c5fa |
g_autoptr(GTimer) timer = g_timer_new ();
|
|
Packit Service |
a3c5fa |
XbSiloQueryData query_data = {
|
|
Packit Service |
a3c5fa |
.sn = NULL,
|
|
Packit Service |
a3c5fa |
.position = 0,
|
|
Packit Service |
a3c5fa |
};
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* empty silo */
|
|
Packit Service |
a3c5fa |
if (xb_silo_is_empty (self)) {
|
|
Packit Service |
a3c5fa |
g_set_error_literal (error,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR_NOT_FOUND,
|
|
Packit Service |
a3c5fa |
"silo has no data");
|
|
Packit Service |
a3c5fa |
return NULL;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* subtree query */
|
|
Packit Service |
a3c5fa |
if (n != NULL)
|
|
Packit Service |
a3c5fa |
sn = xb_node_get_sn (n);
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* only one query allowed */
|
|
Packit Service |
a3c5fa |
if (!xb_silo_query_part (self, sn, results, results_hash,
|
|
Packit Service |
a3c5fa |
query, &query_data, error))
|
|
Packit Service |
a3c5fa |
return NULL;
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* profile */
|
|
Packit Service |
a3c5fa |
if (xb_silo_get_profile_flags (self) & XB_SILO_PROFILE_FLAG_XPATH) {
|
|
Packit Service |
a3c5fa |
g_autofree gchar *tmp = xb_query_to_string (query);
|
|
Packit Service |
a3c5fa |
xb_silo_add_profile (self, timer,
|
|
Packit Service |
a3c5fa |
"query on %s with `%s` limit=%u -> %u results",
|
|
Packit Service |
a3c5fa |
n != NULL ? xb_node_get_element (n) : "/",
|
|
Packit Service |
a3c5fa |
tmp,
|
|
Packit Service |
a3c5fa |
xb_query_get_limit (query),
|
|
Packit Service |
a3c5fa |
results->len);
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* nothing found */
|
|
Packit Service |
a3c5fa |
if (results->len == 0) {
|
|
Packit Service |
a3c5fa |
g_autofree gchar *tmp = xb_query_to_string (query);
|
|
Packit Service |
a3c5fa |
g_set_error (error,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR_NOT_FOUND,
|
|
Packit Service |
a3c5fa |
"no results for XPath query '%s'",
|
|
Packit Service |
a3c5fa |
tmp);
|
|
Packit Service |
a3c5fa |
return NULL;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* reverse order */
|
|
Packit Service |
a3c5fa |
if (xb_query_get_flags (query) & XB_QUERY_FLAG_REVERSE)
|
|
Packit Service |
a3c5fa |
_g_ptr_array_reverse (results);
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
return g_steal_pointer (&results);
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/**
|
|
Packit Service |
a3c5fa |
* xb_silo_query_full:
|
|
Packit Service |
a3c5fa |
* @self: a #XbSilo
|
|
Packit Service |
a3c5fa |
* @query: an #XbQuery
|
|
Packit Service |
a3c5fa |
* @error: the #GError, or %NULL
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Searches the silo using an XPath query.
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* It is safe to call this function from a different thread to the one that
|
|
Packit Service |
a3c5fa |
* created the #XbSilo.
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Please note: Only a subset of XPath is supported.
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Returns: (transfer container) (element-type XbNode): results, or %NULL if unfound
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Since: 0.1.13
|
|
Packit Service |
a3c5fa |
**/
|
|
Packit Service |
a3c5fa |
GPtrArray *
|
|
Packit Service |
a3c5fa |
xb_silo_query_full (XbSilo *self, XbQuery *query, GError **error)
|
|
Packit Service |
a3c5fa |
{
|
|
Packit Service |
a3c5fa |
g_return_val_if_fail (XB_IS_SILO (self), NULL);
|
|
Packit Service |
a3c5fa |
g_return_val_if_fail (XB_IS_QUERY (query), NULL);
|
|
Packit Service |
a3c5fa |
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
|
Packit Service |
a3c5fa |
return xb_silo_query_with_root_full (self, NULL, query, error);
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/**
|
|
Packit Service |
a3c5fa |
* xb_silo_query_first_full:
|
|
Packit Service |
a3c5fa |
* @self: a #XbSilo
|
|
Packit Service |
a3c5fa |
* @query: an #XbQuery
|
|
Packit Service |
a3c5fa |
* @error: the #GError, or %NULL
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Searches the silo using an XPath query, returning up to one result.
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* It is safe to call this function from a different thread to the one that
|
|
Packit Service |
a3c5fa |
* created the #XbSilo.
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Please note: Only a tiny subset of XPath 1.0 is supported.
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Returns: (transfer none): a #XbNode, or %NULL if unfound
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Since: 0.1.13
|
|
Packit Service |
a3c5fa |
**/
|
|
Packit Service |
a3c5fa |
XbNode *
|
|
Packit Service |
a3c5fa |
xb_silo_query_first_full (XbSilo *self, XbQuery *query, GError **error)
|
|
Packit Service |
a3c5fa |
{
|
|
Packit Service |
a3c5fa |
g_autoptr(GPtrArray) results = NULL;
|
|
Packit Service |
a3c5fa |
results = xb_silo_query_full (self, query, error);
|
|
Packit Service |
a3c5fa |
if (results == NULL)
|
|
Packit Service |
a3c5fa |
return NULL;
|
|
Packit Service |
a3c5fa |
return g_object_ref (g_ptr_array_index (results, 0));
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/**
|
|
Packit Service |
a3c5fa |
* xb_silo_query:
|
|
Packit Service |
a3c5fa |
* @self: a #XbSilo
|
|
Packit Service |
a3c5fa |
* @xpath: an XPath, e.g. `/components/component[@type=desktop]/id[abe.desktop]`
|
|
Packit Service |
a3c5fa |
* @limit: maximum number of results to return, or 0 for "all"
|
|
Packit Service |
a3c5fa |
* @error: the #GError, or %NULL
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Searches the silo using an XPath query, returning up to @limit results.
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* It is safe to call this function from a different thread to the one that
|
|
Packit Service |
a3c5fa |
* created the #XbSilo.
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Please note: Only a subset of XPath is supported.
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Returns: (transfer container) (element-type XbNode): results, or %NULL if unfound
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Since: 0.1.0
|
|
Packit Service |
a3c5fa |
**/
|
|
Packit Service |
a3c5fa |
GPtrArray *
|
|
Packit Service |
a3c5fa |
xb_silo_query (XbSilo *self, const gchar *xpath, guint limit, GError **error)
|
|
Packit Service |
a3c5fa |
{
|
|
Packit Service |
a3c5fa |
g_return_val_if_fail (XB_IS_SILO (self), NULL);
|
|
Packit Service |
a3c5fa |
g_return_val_if_fail (xpath != NULL, NULL);
|
|
Packit Service |
a3c5fa |
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
|
Packit Service |
a3c5fa |
return xb_silo_query_with_root (self, NULL, xpath, limit, error);
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/**
|
|
Packit Service |
a3c5fa |
* xb_silo_query_first:
|
|
Packit Service |
a3c5fa |
* @self: a #XbSilo
|
|
Packit Service |
a3c5fa |
* @xpath: An XPath, e.g. `/components/component[@type=desktop]/id[abe.desktop]`
|
|
Packit Service |
a3c5fa |
* @error: the #GError, or %NULL
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Searches the silo using an XPath query, returning up to one result.
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* It is safe to call this function from a different thread to the one that
|
|
Packit Service |
a3c5fa |
* created the #XbSilo.
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Please note: Only a tiny subset of XPath 1.0 is supported.
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Returns: (transfer none): a #XbNode, or %NULL if unfound
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Since: 0.1.0
|
|
Packit Service |
a3c5fa |
**/
|
|
Packit Service |
a3c5fa |
XbNode *
|
|
Packit Service |
a3c5fa |
xb_silo_query_first (XbSilo *self, const gchar *xpath, GError **error)
|
|
Packit Service |
a3c5fa |
{
|
|
Packit Service |
a3c5fa |
g_autoptr(GPtrArray) results = NULL;
|
|
Packit Service |
a3c5fa |
results = xb_silo_query_with_root (self, NULL, xpath, 1, error);
|
|
Packit Service |
a3c5fa |
if (results == NULL)
|
|
Packit Service |
a3c5fa |
return NULL;
|
|
Packit Service |
a3c5fa |
return g_object_ref (g_ptr_array_index (results, 0));
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/**
|
|
Packit Service |
a3c5fa |
* xb_silo_query_build_index:
|
|
Packit Service |
a3c5fa |
* @self: a #XbSilo
|
|
Packit Service |
a3c5fa |
* @xpath: An XPath, e.g. `/components/component[@type=desktop]/id[abe.desktop]`
|
|
Packit Service |
a3c5fa |
* @attr: (nullable): Attribute name, e.g. `type`, or NULL
|
|
Packit Service |
a3c5fa |
* @error: the #GError, or %NULL
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Adds the `attr()` or `text()` results of a query to the index.
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Returns: %TRUE for success
|
|
Packit Service |
a3c5fa |
*
|
|
Packit Service |
a3c5fa |
* Since: 0.1.4
|
|
Packit Service |
a3c5fa |
**/
|
|
Packit Service |
a3c5fa |
gboolean
|
|
Packit Service |
a3c5fa |
xb_silo_query_build_index (XbSilo *self,
|
|
Packit Service |
a3c5fa |
const gchar *xpath,
|
|
Packit Service |
a3c5fa |
const gchar *attr,
|
|
Packit Service |
a3c5fa |
GError **error)
|
|
Packit Service |
a3c5fa |
{
|
|
Packit Service |
a3c5fa |
g_autoptr(GError) error_local = NULL;
|
|
Packit Service |
a3c5fa |
g_autoptr(GPtrArray) array = NULL;
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
g_return_val_if_fail (XB_IS_SILO (self), FALSE);
|
|
Packit Service |
a3c5fa |
g_return_val_if_fail (xpath != NULL, FALSE);
|
|
Packit Service |
a3c5fa |
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* do the query */
|
|
Packit Service |
a3c5fa |
array = xb_silo_query_with_root (self, NULL, xpath, 0, &error_local);
|
|
Packit Service |
a3c5fa |
if (array == NULL) {
|
|
Packit Service |
a3c5fa |
if (g_error_matches (error_local,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR_INVALID_ARGUMENT) ||
|
|
Packit Service |
a3c5fa |
g_error_matches (error_local,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR,
|
|
Packit Service |
a3c5fa |
G_IO_ERROR_NOT_FOUND)) {
|
|
Packit Service |
a3c5fa |
g_debug ("ignoring index: %s", error_local->message);
|
|
Packit Service |
a3c5fa |
return TRUE;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
g_propagate_error (error, g_steal_pointer (&error_local));
|
|
Packit Service |
a3c5fa |
return FALSE;
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* add each attribute name AND value */
|
|
Packit Service |
a3c5fa |
for (guint i = 0; i < array->len; i++) {
|
|
Packit Service |
a3c5fa |
XbNode *n = g_ptr_array_index (array, i);
|
|
Packit Service |
a3c5fa |
XbSiloNode *sn = xb_node_get_sn (n);
|
|
Packit Service |
a3c5fa |
if (attr != NULL) {
|
|
Packit Service |
a3c5fa |
guint32 off = xb_silo_get_offset_for_node (self, sn);
|
|
Packit Service |
a3c5fa |
for (guint8 j = 0; j < sn->nr_attrs; j++) {
|
|
Packit Service |
a3c5fa |
XbSiloAttr *a = xb_silo_get_attr (self, off, j);
|
|
Packit Service |
a3c5fa |
xb_silo_strtab_index_insert (self, a->attr_name);
|
|
Packit Service |
a3c5fa |
xb_silo_strtab_index_insert (self, a->attr_value);
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
} else {
|
|
Packit Service |
a3c5fa |
xb_silo_strtab_index_insert (self, sn->text);
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
}
|
|
Packit Service |
a3c5fa |
|
|
Packit Service |
a3c5fa |
/* success */
|
|
Packit Service |
a3c5fa |
return TRUE;
|
|
Packit Service |
a3c5fa |
}
|