/* common-fts-search-query.c generated by valac 0.56.3, the Vala compiler
 * generated from common-fts-search-query.vala, do not modify */

/*
 * Copyright © 2016 Software Freedom Conservancy Inc.
 * Copyright © 2019-2020 Michael Gratton <mike@vee.net>.
 *
 * This software is licensed under the GNU Lesser General Public License
 * (version 2.1 or later). See the COPYING file in this distribution.
 */

#include "geary-engine.h"
#include <glib-object.h>
#include <glib.h>
#include "libstemmer.h"
#include <stdlib.h>
#include <string.h>
#include <gee.h>

#define GEARY_FTS_SEARCH_QUERY_EMAIL_TEXT_STEMMED_TERMS "geary-stemmed-terms"

#define GEARY_TYPE_FTS_SEARCH_QUERY (geary_fts_search_query_get_type ())
#define GEARY_FTS_SEARCH_QUERY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEARY_TYPE_FTS_SEARCH_QUERY, GearyFtsSearchQuery))
#define GEARY_FTS_SEARCH_QUERY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEARY_TYPE_FTS_SEARCH_QUERY, GearyFtsSearchQueryClass))
#define GEARY_IS_FTS_SEARCH_QUERY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEARY_TYPE_FTS_SEARCH_QUERY))
#define GEARY_IS_FTS_SEARCH_QUERY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEARY_TYPE_FTS_SEARCH_QUERY))
#define GEARY_FTS_SEARCH_QUERY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEARY_TYPE_FTS_SEARCH_QUERY, GearyFtsSearchQueryClass))

typedef struct _GearyFtsSearchQuery GearyFtsSearchQuery;
typedef struct _GearyFtsSearchQueryClass GearyFtsSearchQueryClass;
typedef struct _GearyFtsSearchQueryPrivate GearyFtsSearchQueryPrivate;
enum  {
	GEARY_FTS_SEARCH_QUERY_0_PROPERTY,
	GEARY_FTS_SEARCH_QUERY_HAS_STEMMED_TERMS_PROPERTY,
	GEARY_FTS_SEARCH_QUERY_NUM_PROPERTIES
};
static GParamSpec* geary_fts_search_query_properties[GEARY_FTS_SEARCH_QUERY_NUM_PROPERTIES];
#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
#define _g_free0(var) (var = (g_free (var), NULL))
#define _g_string_free0(var) ((var == NULL) ? NULL : (var = (g_string_free (var, TRUE), NULL)))

struct _GearyFtsSearchQuery {
	GearySearchQuery parent_instance;
	GearyFtsSearchQueryPrivate * priv;
};

struct _GearyFtsSearchQueryClass {
	GearySearchQueryClass parent_class;
};

struct _GearyFtsSearchQueryPrivate {
	gboolean _has_stemmed_terms;
	gboolean is_all_negated;
	struct sb_stemmer* stemmer;
};

static gint GearyFtsSearchQuery_private_offset;
static gpointer geary_fts_search_query_parent_class = NULL;

VALA_EXTERN GType geary_fts_search_query_get_type (void) G_GNUC_CONST ;
VALA_EXTERN gboolean geary_fts_search_query_get_has_stemmed_terms (GearyFtsSearchQuery* self);
static void geary_fts_search_query_set_has_stemmed_terms (GearyFtsSearchQuery* self,
                                                   gboolean value);
VALA_EXTERN GearyFtsSearchQuery* geary_fts_search_query_new (GeeList* expression,
                                                 const gchar* raw,
                                                 struct sb_stemmer* stemmer);
VALA_EXTERN GearyFtsSearchQuery* geary_fts_search_query_construct (GType object_type,
                                                       GeeList* expression,
                                                       const gchar* raw,
                                                       struct sb_stemmer* stemmer);
VALA_EXTERN gboolean geary_search_query_strategy_is_stemming_enabled (GearySearchQueryStrategy self);
static void geary_fts_search_query_stem_search_terms (GearyFtsSearchQuery* self,
                                               GearySearchQueryEmailTextTerm* text);
VALA_EXTERN GearyDbStatement* geary_fts_search_query_get_search_query (GearyFtsSearchQuery* self,
                                                           GearyDbConnection* cx,
                                                           const gchar* search_ids_sql,
                                                           const gchar* excluded_folder_ids_sql,
                                                           gboolean exclude_folderless,
                                                           gint limit,
                                                           gint offset,
                                                           GError** error);
static gboolean geary_fts_search_query_sql_add_term_conditions (GearyFtsSearchQuery* self,
                                                         GString* sql,
                                                         gboolean have_added_sql_condition);
static gint geary_fts_search_query_sql_bind_term_conditions (GearyFtsSearchQuery* self,
                                                      GearyDbStatement* sql,
                                                      gint index,
                                                      GError** error);
VALA_EXTERN GearyDbStatement* geary_fts_search_query_get_match_query (GearyFtsSearchQuery* self,
                                                          GearyDbConnection* cx,
                                                          const gchar* search_ids_sql,
                                                          GError** error);
VALA_EXTERN gint geary_search_query_strategy_get_min_term_length_for_stemming (GearySearchQueryStrategy self);
VALA_EXTERN gint geary_search_query_strategy_get_max_difference_term_stem_lengths (GearySearchQueryStrategy self);
static inline void geary_fts_search_query_sql_add_term_condition (GearyFtsSearchQuery* self,
                                                    GString* sql,
                                                    GearySearchQueryTerm* term);
static inline void geary_fts_search_query_sql_add_email_text_term_conditions (GearyFtsSearchQuery* self,
                                                                GearySearchQueryEmailTextTerm* text,
                                                                GString* sql);
static inline gint geary_fts_search_query_sql_bind_term_condition (GearyFtsSearchQuery* self,
                                                     GearyDbStatement* sql,
                                                     GearySearchQueryTerm* term,
                                                     gint index,
                                                     GError** error);
static void geary_fts_search_query_finalize (GObject * obj);
static GType geary_fts_search_query_get_type_once (void);
static void _vala_geary_fts_search_query_get_property (GObject * object,
                                                guint property_id,
                                                GValue * value,
                                                GParamSpec * pspec);
static void _vala_geary_fts_search_query_set_property (GObject * object,
                                                guint property_id,
                                                const GValue * value,
                                                GParamSpec * pspec);

static inline gpointer
geary_fts_search_query_get_instance_private (GearyFtsSearchQuery* self)
{
	return G_STRUCT_MEMBER_P (self, GearyFtsSearchQuery_private_offset);
}

gboolean
geary_fts_search_query_get_has_stemmed_terms (GearyFtsSearchQuery* self)
{
	gboolean result;
	g_return_val_if_fail (GEARY_IS_FTS_SEARCH_QUERY (self), FALSE);
	result = self->priv->_has_stemmed_terms;
	return result;
}

static void
geary_fts_search_query_set_has_stemmed_terms (GearyFtsSearchQuery* self,
                                              gboolean value)
{
	gboolean old_value;
	g_return_if_fail (GEARY_IS_FTS_SEARCH_QUERY (self));
	old_value = geary_fts_search_query_get_has_stemmed_terms (self);
	if (old_value != value) {
		self->priv->_has_stemmed_terms = value;
		g_object_notify_by_pspec ((GObject *) self, geary_fts_search_query_properties[GEARY_FTS_SEARCH_QUERY_HAS_STEMMED_TERMS_PROPERTY]);
	}
}

static gpointer
_g_object_ref0 (gpointer self)
{
	return self ? g_object_ref (self) : NULL;
}

GearyFtsSearchQuery*
geary_fts_search_query_construct (GType object_type,
                                  GeeList* expression,
                                  const gchar* raw,
                                  struct sb_stemmer* stemmer)
{
	GearyFtsSearchQuery * self = NULL;
	g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (expression, GEE_TYPE_LIST), NULL);
	g_return_val_if_fail (raw != NULL, NULL);
	g_return_val_if_fail (stemmer != NULL, NULL);
	self = (GearyFtsSearchQuery*) geary_search_query_construct (object_type, G_TYPE_CHECK_INSTANCE_CAST (expression, GEE_TYPE_COLLECTION, GeeCollection), raw);
	self->priv->stemmer = stemmer;
	{
		GeeList* _term_list = NULL;
		GeeList* _tmp0_;
		GeeList* _tmp1_;
		gint _term_size = 0;
		GeeList* _tmp2_;
		gint _tmp3_;
		gint _tmp4_;
		gint _term_index = 0;
		_tmp0_ = geary_search_query_get_expression (G_TYPE_CHECK_INSTANCE_CAST (self, GEARY_TYPE_SEARCH_QUERY, GearySearchQuery));
		_tmp1_ = _tmp0_;
		_term_list = _tmp1_;
		_tmp2_ = _term_list;
		_tmp3_ = gee_collection_get_size (G_TYPE_CHECK_INSTANCE_CAST (_tmp2_, GEE_TYPE_COLLECTION, GeeCollection));
		_tmp4_ = _tmp3_;
		_term_size = _tmp4_;
		_term_index = -1;
		while (TRUE) {
			gint _tmp5_;
			gint _tmp6_;
			GearySearchQueryTerm* term = NULL;
			GeeList* _tmp7_;
			gpointer _tmp8_;
			GearySearchQueryTerm* _tmp9_;
			GearySearchQueryTerm* _tmp16_;
			gboolean _tmp17_;
			gboolean _tmp18_;
			_term_index = _term_index + 1;
			_tmp5_ = _term_index;
			_tmp6_ = _term_size;
			if (!(_tmp5_ < _tmp6_)) {
				break;
			}
			_tmp7_ = _term_list;
			_tmp8_ = gee_list_get (_tmp7_, _term_index);
			term = (GearySearchQueryTerm*) _tmp8_;
			_tmp9_ = term;
			if (G_TYPE_FROM_INSTANCE (G_TYPE_CHECK_INSTANCE_CAST (_tmp9_, G_TYPE_OBJECT, GObject)) == GEARY_SEARCH_QUERY_TYPE_EMAIL_TEXT_TERM) {
				GearySearchQueryEmailTextTerm* text = NULL;
				GearySearchQueryTerm* _tmp10_;
				GearySearchQueryEmailTextTerm* _tmp11_;
				GearySearchQueryEmailTextTerm* _tmp12_;
				GearySearchQueryStrategy _tmp13_;
				GearySearchQueryStrategy _tmp14_;
				_tmp10_ = term;
				_tmp11_ = _g_object_ref0 (G_TYPE_CHECK_INSTANCE_CAST (_tmp10_, GEARY_SEARCH_QUERY_TYPE_EMAIL_TEXT_TERM, GearySearchQueryEmailTextTerm));
				text = _tmp11_;
				_tmp12_ = text;
				_tmp13_ = geary_search_query_email_text_term_get_matching_strategy (_tmp12_);
				_tmp14_ = _tmp13_;
				if (geary_search_query_strategy_is_stemming_enabled (_tmp14_)) {
					GearySearchQueryEmailTextTerm* _tmp15_;
					_tmp15_ = text;
					geary_fts_search_query_stem_search_terms (self, _tmp15_);
				}
				_g_object_unref0 (text);
			}
			_tmp16_ = term;
			_tmp17_ = geary_search_query_term_get_is_negated (_tmp16_);
			_tmp18_ = _tmp17_;
			if (!_tmp18_) {
				self->priv->is_all_negated = FALSE;
			}
			_g_object_unref0 (term);
		}
	}
	return self;
}

GearyFtsSearchQuery*
geary_fts_search_query_new (GeeList* expression,
                            const gchar* raw,
                            struct sb_stemmer* stemmer)
{
	return geary_fts_search_query_construct (GEARY_TYPE_FTS_SEARCH_QUERY, expression, raw, stemmer);
}

GearyDbStatement*
geary_fts_search_query_get_search_query (GearyFtsSearchQuery* self,
                                         GearyDbConnection* cx,
                                         const gchar* search_ids_sql,
                                         const gchar* excluded_folder_ids_sql,
                                         gboolean exclude_folderless,
                                         gint limit,
                                         gint offset,
                                         GError** error)
{
	GString* sql = NULL;
	GString* _tmp0_;
	GString* _tmp1_;
	gboolean conditions_added = FALSE;
	GString* _tmp4_;
	GeeList* _tmp6_;
	GeeList* _tmp7_;
	gboolean _tmp8_;
	gboolean _tmp9_;
	GString* _tmp21_;
	GString* _tmp22_;
	GearyDbStatement* stmt = NULL;
	GString* _tmp24_;
	const gchar* _tmp25_;
	GearyDbStatement* _tmp26_;
	gint bind_index = 0;
	GearyDbStatement* _tmp27_;
	GError* _inner_error0_ = NULL;
	GearyDbStatement* result;
	g_return_val_if_fail (GEARY_IS_FTS_SEARCH_QUERY (self), NULL);
	g_return_val_if_fail (GEARY_DB_IS_CONNECTION (cx), NULL);
	_tmp0_ = g_string_new ("");
	sql = _tmp0_;
	_tmp1_ = sql;
	g_string_append (_tmp1_, "\n" \
"                SELECT DISTINCT mt.id\n" \
"                FROM MessageTable AS mt\n" \
"                INDEXED BY MessageTableInternalDateTimeTIndex");
	if (exclude_folderless) {
		GString* _tmp2_;
		_tmp2_ = sql;
		g_string_append (_tmp2_, "\n" \
"                INNER JOIN MessageLocationTable AS mlt ON mt.id = mlt." \
"message_id");
	} else {
		GString* _tmp3_;
		_tmp3_ = sql;
		g_string_append (_tmp3_, "\n" \
"                LEFT JOIN MessageLocationTable AS mlt ON mt.id = mlt.m" \
"essage_id");
	}
	conditions_added = FALSE;
	_tmp4_ = sql;
	g_string_append (_tmp4_, "\n                WHERE");
	if (excluded_folder_ids_sql != NULL) {
		GString* _tmp5_;
		_tmp5_ = sql;
		g_string_append_printf (_tmp5_, " mlt.folder_id NOT IN (%s)", excluded_folder_ids_sql);
		conditions_added = TRUE;
	}
	_tmp6_ = geary_search_query_get_expression (G_TYPE_CHECK_INSTANCE_CAST (self, GEARY_TYPE_SEARCH_QUERY, GearySearchQuery));
	_tmp7_ = _tmp6_;
	_tmp8_ = gee_collection_get_is_empty (G_TYPE_CHECK_INSTANCE_CAST (_tmp7_, GEE_TYPE_COLLECTION, GeeCollection));
	_tmp9_ = _tmp8_;
	if (!_tmp9_) {
		const gchar* _tmp11_ = NULL;
		GString* _tmp12_;
		GString* _tmp13_;
		GString* _tmp14_;
		GString* _tmp15_;
		if (conditions_added) {
			GString* _tmp10_;
			_tmp10_ = sql;
			g_string_append (_tmp10_, " AND");
		}
		if (self->priv->is_all_negated) {
			_tmp11_ = " mt.id NOT IN";
		} else {
			_tmp11_ = " mt.id IN";
		}
		_tmp12_ = sql;
		g_string_append (_tmp12_, _tmp11_);
		_tmp13_ = sql;
		g_string_append (_tmp13_, " (SELECT mst.rowid FROM MessageSearchTable as mst WHERE ");
		_tmp14_ = sql;
		geary_fts_search_query_sql_add_term_conditions (self, _tmp14_, FALSE);
		_tmp15_ = sql;
		g_string_append_c (_tmp15_, ')');
		conditions_added = TRUE;
	}
	if (!geary_string_is_empty (search_ids_sql)) {
		GString* _tmp17_;
		gchar* _tmp18_;
		gchar* _tmp19_;
		if (conditions_added) {
			GString* _tmp16_;
			_tmp16_ = sql;
			g_string_append (_tmp16_, " AND");
		}
		_tmp17_ = sql;
		_tmp18_ = g_strdup_printf (" mt.id IN (%s)", search_ids_sql);
		_tmp19_ = _tmp18_;
		g_string_append (_tmp17_, _tmp19_);
		_g_free0 (_tmp19_);
	}
	if (conditions_added) {
		GString* _tmp20_;
		_tmp20_ = sql;
		g_string_append (_tmp20_, " AND");
	}
	_tmp21_ = sql;
	g_string_append (_tmp21_, " mlt.remove_marker IN (0, null)");
	_tmp22_ = sql;
	g_string_append (_tmp22_, "\n                ORDER BY mt.internaldate_time_t DESC");
	if (limit > 0) {
		GString* _tmp23_;
		_tmp23_ = sql;
		g_string_append (_tmp23_, "\n                LIMIT ? OFFSET ?");
	}
	_tmp24_ = sql;
	_tmp25_ = _tmp24_->str;
	_tmp26_ = geary_db_connection_prepare (cx, _tmp25_, &_inner_error0_);
	stmt = _tmp26_;
	if (G_UNLIKELY (_inner_error0_ != NULL)) {
		g_propagate_error (error, _inner_error0_);
		_g_string_free0 (sql);
		return NULL;
	}
	_tmp27_ = stmt;
	bind_index = geary_fts_search_query_sql_bind_term_conditions (self, _tmp27_, 0, &_inner_error0_);
	if (G_UNLIKELY (_inner_error0_ != NULL)) {
		g_propagate_error (error, _inner_error0_);
		_g_object_unref0 (stmt);
		_g_string_free0 (sql);
		return NULL;
	}
	if (limit > 0) {
		GearyDbStatement* _tmp28_;
		gint _tmp29_;
		gint _tmp30_;
		GearyDbStatement* _tmp31_;
		GearyDbStatement* _tmp32_;
		GearyDbStatement* _tmp33_;
		gint _tmp34_;
		gint _tmp35_;
		GearyDbStatement* _tmp36_;
		GearyDbStatement* _tmp37_;
		_tmp28_ = stmt;
		_tmp29_ = bind_index;
		bind_index = _tmp29_ + 1;
		_tmp30_ = limit;
		_tmp31_ = geary_db_statement_bind_int (_tmp28_, _tmp29_, _tmp30_, &_inner_error0_);
		_tmp32_ = _tmp31_;
		_g_object_unref0 (_tmp32_);
		if (G_UNLIKELY (_inner_error0_ != NULL)) {
			g_propagate_error (error, _inner_error0_);
			_g_object_unref0 (stmt);
			_g_string_free0 (sql);
			return NULL;
		}
		_tmp33_ = stmt;
		_tmp34_ = bind_index;
		bind_index = _tmp34_ + 1;
		_tmp35_ = offset;
		_tmp36_ = geary_db_statement_bind_int (_tmp33_, _tmp34_, _tmp35_, &_inner_error0_);
		_tmp37_ = _tmp36_;
		_g_object_unref0 (_tmp37_);
		if (G_UNLIKELY (_inner_error0_ != NULL)) {
			g_propagate_error (error, _inner_error0_);
			_g_object_unref0 (stmt);
			_g_string_free0 (sql);
			return NULL;
		}
	}
	result = stmt;
	_g_string_free0 (sql);
	return result;
}

GearyDbStatement*
geary_fts_search_query_get_match_query (GearyFtsSearchQuery* self,
                                        GearyDbConnection* cx,
                                        const gchar* search_ids_sql,
                                        GError** error)
{
	GString* sql = NULL;
	GString* _tmp0_;
	GString* _tmp1_;
	GString* _tmp2_;
	GString* _tmp3_;
	GString* _tmp4_;
	GearyDbStatement* stmt = NULL;
	GString* _tmp5_;
	const gchar* _tmp6_;
	GearyDbStatement* _tmp7_;
	GearyDbStatement* _tmp8_;
	GError* _inner_error0_ = NULL;
	GearyDbStatement* result;
	g_return_val_if_fail (GEARY_IS_FTS_SEARCH_QUERY (self), NULL);
	g_return_val_if_fail (GEARY_DB_IS_CONNECTION (cx), NULL);
	_tmp0_ = g_string_new ("");
	sql = _tmp0_;
	_tmp1_ = sql;
	g_string_append (_tmp1_, "\n" \
"            SELECT mst.rowid, geary_matches(MessageSearchTable)\n" \
"            FROM MessageSearchTable as mst\n" \
"            WHERE rowid IN (\n" \
"        ");
	_tmp2_ = sql;
	g_string_append (_tmp2_, search_ids_sql);
	_tmp3_ = sql;
	g_string_append (_tmp3_, ") AND ");
	_tmp4_ = sql;
	geary_fts_search_query_sql_add_term_conditions (self, _tmp4_, FALSE);
	_tmp5_ = sql;
	_tmp6_ = _tmp5_->str;
	_tmp7_ = geary_db_connection_prepare (cx, _tmp6_, &_inner_error0_);
	stmt = _tmp7_;
	if (G_UNLIKELY (_inner_error0_ != NULL)) {
		g_propagate_error (error, _inner_error0_);
		_g_string_free0 (sql);
		return NULL;
	}
	_tmp8_ = stmt;
	geary_fts_search_query_sql_bind_term_conditions (self, _tmp8_, 0, &_inner_error0_);
	if (G_UNLIKELY (_inner_error0_ != NULL)) {
		g_propagate_error (error, _inner_error0_);
		_g_object_unref0 (stmt);
		_g_string_free0 (sql);
		return NULL;
	}
	result = stmt;
	_g_string_free0 (sql);
	return result;
}

/**
     * Applies stemming for the given term to a specific term value.
     *
     * Prior experience with the Snowball stemmer indicates it is too
     * aggressive for our tastes when coupled with prefix-matching of
     * all unquoted terms. See
     * https://bugzilla.gnome.org/show_bug.cgi?id=713179 and
     * https://bugzilla.gnome.org/show_bug.cgi?id=720361
     *
     * This method is part of a larger strategy designed to dampen
     * that aggressiveness without losing the benefits of stemming
     * entirely: The database's FTS table uses no stemming, but
     * libstemmer is used to generate stemmed search terms.
     * Post-search processing is then to strip results which are too
     * "greedy" due to prefix-matching the stemmed variant.
     *
     * Some heuristics are in place simply to determine if stemming
     * should occur:
     *
     * # If stemming is unallowed, no stemming occurs.
     * # If the term is < min. term length for stemming, no stemming
     *   occurs.
     * # If the stemmer returns a stem that is the same as the
     *   original term, no stemming occurs.
     * # If the difference between the stemmed word and the original
     *   term is more than maximum allowed, no stemming occurs.  This
     *   works under the assumption that if the user has typed a long
     *   word, they do not want to "go back" to searching for a much
     *   shorter version of it.  (For example, "accountancies" stems
     *   to "account").
     *
     * Otherwise, the stem for the term is returned.
     */
static const gchar*
string_to_string (const gchar* self)
{
	const gchar* result;
	g_return_val_if_fail (self != NULL, NULL);
	result = self;
	return result;
}

static void
geary_fts_search_query_stem_search_terms (GearyFtsSearchQuery* self,
                                          GearySearchQueryEmailTextTerm* text)
{
	GeeArrayList* stemmed_terms = NULL;
	GeeArrayList* _tmp0_;
	GeeArrayList* _tmp42_;
	GeeArrayList* _tmp43_;
	g_return_if_fail (GEARY_IS_FTS_SEARCH_QUERY (self));
	g_return_if_fail (GEARY_SEARCH_QUERY_IS_EMAIL_TEXT_TERM (text));
	_tmp0_ = gee_array_list_new (G_TYPE_STRING, (GBoxedCopyFunc) g_strdup, (GDestroyNotify) g_free, NULL, NULL, NULL);
	stemmed_terms = _tmp0_;
	{
		GeeList* _term_list = NULL;
		GeeList* _tmp1_;
		GeeList* _tmp2_;
		gint _term_size = 0;
		GeeList* _tmp3_;
		gint _tmp4_;
		gint _tmp5_;
		gint _term_index = 0;
		_tmp1_ = geary_search_query_email_text_term_get_terms (text);
		_tmp2_ = _tmp1_;
		_term_list = _tmp2_;
		_tmp3_ = _term_list;
		_tmp4_ = gee_collection_get_size (G_TYPE_CHECK_INSTANCE_CAST (_tmp3_, GEE_TYPE_COLLECTION, GeeCollection));
		_tmp5_ = _tmp4_;
		_term_size = _tmp5_;
		_term_index = -1;
		while (TRUE) {
			gint _tmp6_;
			gint _tmp7_;
			gchar* term = NULL;
			GeeList* _tmp8_;
			gpointer _tmp9_;
			gint term_length = 0;
			const gchar* _tmp10_;
			gint _tmp11_;
			gint _tmp12_;
			gchar* stemmed = NULL;
			GearySearchQueryStrategy _tmp13_;
			GearySearchQueryStrategy _tmp14_;
			const gchar* _tmp29_;
			GeeArrayList* _tmp40_;
			const gchar* _tmp41_;
			_term_index = _term_index + 1;
			_tmp6_ = _term_index;
			_tmp7_ = _term_size;
			if (!(_tmp6_ < _tmp7_)) {
				break;
			}
			_tmp8_ = _term_list;
			_tmp9_ = gee_list_get (_tmp8_, _term_index);
			term = (gchar*) _tmp9_;
			_tmp10_ = term;
			_tmp11_ = strlen (_tmp10_);
			_tmp12_ = _tmp11_;
			term_length = _tmp12_;
			stemmed = NULL;
			_tmp13_ = geary_search_query_email_text_term_get_matching_strategy (text);
			_tmp14_ = _tmp13_;
			if (term_length > geary_search_query_strategy_get_min_term_length_for_stemming (_tmp14_)) {
				struct sb_stemmer* _tmp15_;
				const gchar* _tmp16_;
				const gchar* _tmp17_;
				gchar* _tmp18_;
				gboolean _tmp19_ = FALSE;
				gboolean _tmp20_ = FALSE;
				const gchar* _tmp21_;
				_tmp15_ = self->priv->stemmer;
				_tmp16_ = term;
				_tmp17_ = sb_stemmer_stem (_tmp15_, _tmp16_, term_length);
				_tmp18_ = g_strdup (_tmp17_);
				_g_free0 (stemmed);
				stemmed = _tmp18_;
				_tmp21_ = stemmed;
				if (geary_string_is_empty (_tmp21_)) {
					_tmp20_ = TRUE;
				} else {
					const gchar* _tmp22_;
					const gchar* _tmp23_;
					_tmp22_ = term;
					_tmp23_ = stemmed;
					_tmp20_ = g_strcmp0 (_tmp22_, _tmp23_) == 0;
				}
				if (_tmp20_) {
					_tmp19_ = TRUE;
				} else {
					const gchar* _tmp24_;
					gint _tmp25_;
					gint _tmp26_;
					GearySearchQueryStrategy _tmp27_;
					GearySearchQueryStrategy _tmp28_;
					_tmp24_ = stemmed;
					_tmp25_ = strlen (_tmp24_);
					_tmp26_ = _tmp25_;
					_tmp27_ = geary_search_query_email_text_term_get_matching_strategy (text);
					_tmp28_ = _tmp27_;
					_tmp19_ = (term_length - _tmp26_) > geary_search_query_strategy_get_max_difference_term_stem_lengths (_tmp28_);
				}
				if (_tmp19_) {
					_g_free0 (stemmed);
					stemmed = NULL;
				}
			}
			_tmp29_ = stemmed;
			if (_tmp29_ != NULL) {
				const gchar* _tmp30_;
				const gchar* _tmp31_;
				const gchar* _tmp32_;
				const gchar* _tmp33_;
				gchar* _tmp34_;
				gchar* _tmp35_;
				geary_fts_search_query_set_has_stemmed_terms (self, TRUE);
				_tmp30_ = term;
				_tmp31_ = string_to_string (_tmp30_);
				_tmp32_ = stemmed;
				_tmp33_ = string_to_string (_tmp32_);
				_tmp34_ = g_strconcat ("Search term \"", _tmp31_, "\" stemmed to \"", _tmp33_, "\"", NULL);
				_tmp35_ = _tmp34_;
				g_debug ("common-fts-search-query.vala:213: %s", _tmp35_);
				_g_free0 (_tmp35_);
			} else {
				const gchar* _tmp36_;
				const gchar* _tmp37_;
				gchar* _tmp38_;
				gchar* _tmp39_;
				_tmp36_ = term;
				_tmp37_ = string_to_string (_tmp36_);
				_tmp38_ = g_strconcat ("Search term \"", _tmp37_, "\" not stemmed", NULL);
				_tmp39_ = _tmp38_;
				g_debug ("common-fts-search-query.vala:215: %s", _tmp39_);
				_g_free0 (_tmp39_);
			}
			_tmp40_ = stemmed_terms;
			_tmp41_ = stemmed;
			gee_abstract_collection_add (G_TYPE_CHECK_INSTANCE_CAST (_tmp40_, GEE_TYPE_ABSTRACT_COLLECTION, GeeAbstractCollection), _tmp41_);
			_g_free0 (stemmed);
			_g_free0 (term);
		}
	}
	_tmp42_ = stemmed_terms;
	_tmp43_ = _g_object_ref0 (_tmp42_);
	g_object_set_data_full (G_TYPE_CHECK_INSTANCE_CAST (text, G_TYPE_OBJECT, GObject), GEARY_FTS_SEARCH_QUERY_EMAIL_TEXT_STEMMED_TERMS, _tmp43_, g_object_unref);
	_g_object_unref0 (stemmed_terms);
}

static gboolean
geary_fts_search_query_sql_add_term_conditions (GearyFtsSearchQuery* self,
                                                GString* sql,
                                                gboolean have_added_sql_condition)
{
	GeeList* _tmp0_;
	GeeList* _tmp1_;
	gboolean _tmp2_;
	gboolean _tmp3_;
	gboolean result;
	g_return_val_if_fail (GEARY_IS_FTS_SEARCH_QUERY (self), FALSE);
	g_return_val_if_fail (sql != NULL, FALSE);
	_tmp0_ = geary_search_query_get_expression (G_TYPE_CHECK_INSTANCE_CAST (self, GEARY_TYPE_SEARCH_QUERY, GearySearchQuery));
	_tmp1_ = _tmp0_;
	_tmp2_ = gee_collection_get_is_empty (G_TYPE_CHECK_INSTANCE_CAST (_tmp1_, GEE_TYPE_COLLECTION, GeeCollection));
	_tmp3_ = _tmp2_;
	if (!_tmp3_) {
		gboolean is_first_positive_term = FALSE;
		gboolean is_first_negated_term = FALSE;
		if (have_added_sql_condition) {
			g_string_append (sql, " AND");
		}
		have_added_sql_condition = TRUE;
		g_string_append (sql, " MessageSearchTable MATCH '");
		is_first_positive_term = TRUE;
		{
			GeeList* _term_list = NULL;
			GeeList* _tmp4_;
			GeeList* _tmp5_;
			gint _term_size = 0;
			GeeList* _tmp6_;
			gint _tmp7_;
			gint _tmp8_;
			gint _term_index = 0;
			_tmp4_ = geary_search_query_get_expression (G_TYPE_CHECK_INSTANCE_CAST (self, GEARY_TYPE_SEARCH_QUERY, GearySearchQuery));
			_tmp5_ = _tmp4_;
			_term_list = _tmp5_;
			_tmp6_ = _term_list;
			_tmp7_ = gee_collection_get_size (G_TYPE_CHECK_INSTANCE_CAST (_tmp6_, GEE_TYPE_COLLECTION, GeeCollection));
			_tmp8_ = _tmp7_;
			_term_size = _tmp8_;
			_term_index = -1;
			while (TRUE) {
				gint _tmp9_;
				gint _tmp10_;
				GearySearchQueryTerm* term = NULL;
				GeeList* _tmp11_;
				gpointer _tmp12_;
				GearySearchQueryTerm* _tmp13_;
				gboolean _tmp14_;
				gboolean _tmp15_;
				_term_index = _term_index + 1;
				_tmp9_ = _term_index;
				_tmp10_ = _term_size;
				if (!(_tmp9_ < _tmp10_)) {
					break;
				}
				_tmp11_ = _term_list;
				_tmp12_ = gee_list_get (_tmp11_, _term_index);
				term = (GearySearchQueryTerm*) _tmp12_;
				_tmp13_ = term;
				_tmp14_ = geary_search_query_term_get_is_negated (_tmp13_);
				_tmp15_ = _tmp14_;
				if (!_tmp15_) {
					GearySearchQueryTerm* _tmp16_;
					if (is_first_positive_term) {
						g_string_append (sql, " (");
					} else {
						g_string_append (sql, " AND");
					}
					_tmp16_ = term;
					geary_fts_search_query_sql_add_term_condition (self, sql, _tmp16_);
					is_first_positive_term = FALSE;
				}
				_g_object_unref0 (term);
			}
		}
		if (!is_first_positive_term) {
			g_string_append_c (sql, ')');
		}
		is_first_negated_term = TRUE;
		{
			GeeList* _term_list = NULL;
			GeeList* _tmp17_;
			GeeList* _tmp18_;
			gint _term_size = 0;
			GeeList* _tmp19_;
			gint _tmp20_;
			gint _tmp21_;
			gint _term_index = 0;
			_tmp17_ = geary_search_query_get_expression (G_TYPE_CHECK_INSTANCE_CAST (self, GEARY_TYPE_SEARCH_QUERY, GearySearchQuery));
			_tmp18_ = _tmp17_;
			_term_list = _tmp18_;
			_tmp19_ = _term_list;
			_tmp20_ = gee_collection_get_size (G_TYPE_CHECK_INSTANCE_CAST (_tmp19_, GEE_TYPE_COLLECTION, GeeCollection));
			_tmp21_ = _tmp20_;
			_term_size = _tmp21_;
			_term_index = -1;
			while (TRUE) {
				gint _tmp22_;
				gint _tmp23_;
				GearySearchQueryTerm* term = NULL;
				GeeList* _tmp24_;
				gpointer _tmp25_;
				GearySearchQueryTerm* _tmp26_;
				gboolean _tmp27_;
				gboolean _tmp28_;
				_term_index = _term_index + 1;
				_tmp22_ = _term_index;
				_tmp23_ = _term_size;
				if (!(_tmp22_ < _tmp23_)) {
					break;
				}
				_tmp24_ = _term_list;
				_tmp25_ = gee_list_get (_tmp24_, _term_index);
				term = (GearySearchQueryTerm*) _tmp25_;
				_tmp26_ = term;
				_tmp27_ = geary_search_query_term_get_is_negated (_tmp26_);
				_tmp28_ = _tmp27_;
				if (_tmp28_) {
					GearySearchQueryTerm* _tmp29_;
					if (is_first_negated_term) {
						if (!self->priv->is_all_negated) {
							g_string_append (sql, " NOT (");
						} else {
							g_string_append (sql, " (");
						}
					} else {
						g_string_append (sql, " AND");
					}
					_tmp29_ = term;
					geary_fts_search_query_sql_add_term_condition (self, sql, _tmp29_);
					is_first_negated_term = FALSE;
				}
				_g_object_unref0 (term);
			}
		}
		if (!is_first_negated_term) {
			g_string_append_c (sql, ')');
		}
		g_string_append (sql, "'");
	}
	result = have_added_sql_condition;
	return result;
}

static inline void
geary_fts_search_query_sql_add_term_condition (GearyFtsSearchQuery* self,
                                               GString* sql,
                                               GearySearchQueryTerm* term)
{
	g_return_if_fail (GEARY_IS_FTS_SEARCH_QUERY (self));
	g_return_if_fail (sql != NULL);
	g_return_if_fail (GEARY_SEARCH_QUERY_IS_TERM (term));
	if (G_TYPE_FROM_INSTANCE (G_TYPE_CHECK_INSTANCE_CAST (term, G_TYPE_OBJECT, GObject)) == GEARY_SEARCH_QUERY_TYPE_EMAIL_TEXT_TERM) {
		geary_fts_search_query_sql_add_email_text_term_conditions (self, G_TYPE_CHECK_INSTANCE_CAST (term, GEARY_SEARCH_QUERY_TYPE_EMAIL_TEXT_TERM, GearySearchQueryEmailTextTerm), sql);
	} else {
		if (G_TYPE_FROM_INSTANCE (G_TYPE_CHECK_INSTANCE_CAST (term, G_TYPE_OBJECT, GObject)) == GEARY_SEARCH_QUERY_TYPE_EMAIL_FLAG_TERM) {
			g_string_append (sql, " ({flags} : \"' || ? || '\")");
		}
	}
}

static inline void
geary_fts_search_query_sql_add_email_text_term_conditions (GearyFtsSearchQuery* self,
                                                           GearySearchQueryEmailTextTerm* text,
                                                           GString* sql)
{
	gchar* target = NULL;
	gchar* _tmp0_;
	GearySearchQueryEmailTextTermProperty _tmp1_;
	GearySearchQueryEmailTextTermProperty _tmp2_;
	GeeList* values = NULL;
	GeeList* _tmp11_;
	GeeList* _tmp12_;
	GeeList* _tmp13_;
	GeeList* stemmed_values = NULL;
	gconstpointer _tmp14_;
	GeeList* _tmp15_;
	gboolean is_first_disjunct = FALSE;
	g_return_if_fail (GEARY_IS_FTS_SEARCH_QUERY (self));
	g_return_if_fail (GEARY_SEARCH_QUERY_IS_EMAIL_TEXT_TERM (text));
	g_return_if_fail (sql != NULL);
	_tmp0_ = g_strdup ("");
	target = _tmp0_;
	_tmp1_ = geary_search_query_email_text_term_get_target (text);
	_tmp2_ = _tmp1_;
	switch (_tmp2_) {
		case GEARY_SEARCH_QUERY_EMAIL_TEXT_TERM_PROPERTY_ALL:
		{
			gchar* _tmp3_;
			_tmp3_ = g_strdup ("");
			_g_free0 (target);
			target = _tmp3_;
			break;
		}
		case GEARY_SEARCH_QUERY_EMAIL_TEXT_TERM_PROPERTY_TO:
		{
			gchar* _tmp4_;
			_tmp4_ = g_strdup ("receivers");
			_g_free0 (target);
			target = _tmp4_;
			break;
		}
		case GEARY_SEARCH_QUERY_EMAIL_TEXT_TERM_PROPERTY_CC:
		{
			gchar* _tmp5_;
			_tmp5_ = g_strdup ("cc");
			_g_free0 (target);
			target = _tmp5_;
			break;
		}
		case GEARY_SEARCH_QUERY_EMAIL_TEXT_TERM_PROPERTY_BCC:
		{
			gchar* _tmp6_;
			_tmp6_ = g_strdup ("bcc");
			_g_free0 (target);
			target = _tmp6_;
			break;
		}
		case GEARY_SEARCH_QUERY_EMAIL_TEXT_TERM_PROPERTY_FROM:
		{
			gchar* _tmp7_;
			_tmp7_ = g_strdup ("from");
			_g_free0 (target);
			target = _tmp7_;
			break;
		}
		case GEARY_SEARCH_QUERY_EMAIL_TEXT_TERM_PROPERTY_SUBJECT:
		{
			gchar* _tmp8_;
			_tmp8_ = g_strdup ("subject");
			_g_free0 (target);
			target = _tmp8_;
			break;
		}
		case GEARY_SEARCH_QUERY_EMAIL_TEXT_TERM_PROPERTY_BODY:
		{
			gchar* _tmp9_;
			_tmp9_ = g_strdup ("body");
			_g_free0 (target);
			target = _tmp9_;
			break;
		}
		case GEARY_SEARCH_QUERY_EMAIL_TEXT_TERM_PROPERTY_ATTACHMENT_NAME:
		{
			gchar* _tmp10_;
			_tmp10_ = g_strdup ("attachments");
			_g_free0 (target);
			target = _tmp10_;
			break;
		}
		default:
		break;
	}
	g_string_append (sql, " (");
	_tmp11_ = geary_search_query_email_text_term_get_terms (text);
	_tmp12_ = _tmp11_;
	_tmp13_ = _g_object_ref0 (_tmp12_);
	values = _tmp13_;
	_tmp14_ = g_object_get_data (G_TYPE_CHECK_INSTANCE_CAST (text, G_TYPE_OBJECT, GObject), GEARY_FTS_SEARCH_QUERY_EMAIL_TEXT_STEMMED_TERMS);
	_tmp15_ = _g_object_ref0 ((GeeList*) _tmp14_);
	stemmed_values = _tmp15_;
	is_first_disjunct = TRUE;
	{
		gint i = 0;
		i = 0;
		{
			gboolean _tmp16_ = FALSE;
			_tmp16_ = TRUE;
			while (TRUE) {
				GeeList* _tmp18_;
				gint _tmp19_;
				gint _tmp20_;
				const gchar* _tmp21_;
				gboolean _tmp23_ = FALSE;
				GeeList* _tmp24_;
				if (!_tmp16_) {
					gint _tmp17_;
					_tmp17_ = i;
					i = _tmp17_ + 1;
				}
				_tmp16_ = FALSE;
				_tmp18_ = values;
				_tmp19_ = gee_collection_get_size (G_TYPE_CHECK_INSTANCE_CAST (_tmp18_, GEE_TYPE_COLLECTION, GeeCollection));
				_tmp20_ = _tmp19_;
				if (!(i < _tmp20_)) {
					break;
				}
				if (!is_first_disjunct) {
					g_string_append (sql, " OR");
				}
				_tmp21_ = target;
				if (g_strcmp0 (_tmp21_, "") != 0) {
					const gchar* _tmp22_;
					_tmp22_ = target;
					g_string_append_printf (sql, "{%s} :", _tmp22_);
				}
				_tmp24_ = stemmed_values;
				if (_tmp24_ != NULL) {
					GeeList* _tmp25_;
					gpointer _tmp26_;
					gchar* _tmp27_;
					_tmp25_ = stemmed_values;
					_tmp26_ = gee_list_get (_tmp25_, i);
					_tmp27_ = (gchar*) _tmp26_;
					_tmp23_ = _tmp27_ != NULL;
					_g_free0 (_tmp27_);
				} else {
					_tmp23_ = FALSE;
				}
				if (_tmp23_) {
					g_string_append (sql, " \"' || ? || '\" OR \"' || ? || '\"*");
				} else {
					GearySearchQueryStrategy _tmp28_;
					GearySearchQueryStrategy _tmp29_;
					_tmp28_ = geary_search_query_email_text_term_get_matching_strategy (text);
					_tmp29_ = _tmp28_;
					if (_tmp29_ != GEARY_SEARCH_QUERY_STRATEGY_EXACT) {
						g_string_append (sql, " \"' || ? || '\"*");
					} else {
						g_string_append (sql, " \"' || ? || '\"");
					}
				}
				is_first_disjunct = FALSE;
			}
		}
	}
	g_string_append_c (sql, ')');
	_g_object_unref0 (stemmed_values);
	_g_object_unref0 (values);
	_g_free0 (target);
}

static gint
geary_fts_search_query_sql_bind_term_conditions (GearyFtsSearchQuery* self,
                                                 GearyDbStatement* sql,
                                                 gint index,
                                                 GError** error)
{
	gint next_index = 0;
	GError* _inner_error0_ = NULL;
	gint result;
	g_return_val_if_fail (GEARY_IS_FTS_SEARCH_QUERY (self), 0);
	g_return_val_if_fail (GEARY_DB_IS_STATEMENT (sql), 0);
	next_index = index;
	{
		GeeList* _term_list = NULL;
		GeeList* _tmp0_;
		GeeList* _tmp1_;
		gint _term_size = 0;
		GeeList* _tmp2_;
		gint _tmp3_;
		gint _tmp4_;
		gint _term_index = 0;
		_tmp0_ = geary_search_query_get_expression (G_TYPE_CHECK_INSTANCE_CAST (self, GEARY_TYPE_SEARCH_QUERY, GearySearchQuery));
		_tmp1_ = _tmp0_;
		_term_list = _tmp1_;
		_tmp2_ = _term_list;
		_tmp3_ = gee_collection_get_size (G_TYPE_CHECK_INSTANCE_CAST (_tmp2_, GEE_TYPE_COLLECTION, GeeCollection));
		_tmp4_ = _tmp3_;
		_term_size = _tmp4_;
		_term_index = -1;
		while (TRUE) {
			gint _tmp5_;
			gint _tmp6_;
			GearySearchQueryTerm* term = NULL;
			GeeList* _tmp7_;
			gpointer _tmp8_;
			GearySearchQueryTerm* _tmp9_;
			gboolean _tmp10_;
			gboolean _tmp11_;
			_term_index = _term_index + 1;
			_tmp5_ = _term_index;
			_tmp6_ = _term_size;
			if (!(_tmp5_ < _tmp6_)) {
				break;
			}
			_tmp7_ = _term_list;
			_tmp8_ = gee_list_get (_tmp7_, _term_index);
			term = (GearySearchQueryTerm*) _tmp8_;
			_tmp9_ = term;
			_tmp10_ = geary_search_query_term_get_is_negated (_tmp9_);
			_tmp11_ = _tmp10_;
			if (!_tmp11_) {
				gint _tmp12_ = 0;
				GearySearchQueryTerm* _tmp13_;
				_tmp13_ = term;
				_tmp12_ = geary_fts_search_query_sql_bind_term_condition (self, sql, _tmp13_, next_index, &_inner_error0_);
				if (G_UNLIKELY (_inner_error0_ != NULL)) {
					if (_inner_error0_->domain == GEARY_DATABASE_ERROR) {
						gint _tmp14_ = -1;
						g_propagate_error (error, _inner_error0_);
						_g_object_unref0 (term);
						return _tmp14_;
					} else {
						gint _tmp15_ = -1;
						_g_object_unref0 (term);
						g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
						g_clear_error (&_inner_error0_);
						return _tmp15_;
					}
				}
				next_index = _tmp12_;
			}
			_g_object_unref0 (term);
		}
	}
	{
		GeeList* _term_list = NULL;
		GeeList* _tmp16_;
		GeeList* _tmp17_;
		gint _term_size = 0;
		GeeList* _tmp18_;
		gint _tmp19_;
		gint _tmp20_;
		gint _term_index = 0;
		_tmp16_ = geary_search_query_get_expression (G_TYPE_CHECK_INSTANCE_CAST (self, GEARY_TYPE_SEARCH_QUERY, GearySearchQuery));
		_tmp17_ = _tmp16_;
		_term_list = _tmp17_;
		_tmp18_ = _term_list;
		_tmp19_ = gee_collection_get_size (G_TYPE_CHECK_INSTANCE_CAST (_tmp18_, GEE_TYPE_COLLECTION, GeeCollection));
		_tmp20_ = _tmp19_;
		_term_size = _tmp20_;
		_term_index = -1;
		while (TRUE) {
			gint _tmp21_;
			gint _tmp22_;
			GearySearchQueryTerm* term = NULL;
			GeeList* _tmp23_;
			gpointer _tmp24_;
			GearySearchQueryTerm* _tmp25_;
			gboolean _tmp26_;
			gboolean _tmp27_;
			_term_index = _term_index + 1;
			_tmp21_ = _term_index;
			_tmp22_ = _term_size;
			if (!(_tmp21_ < _tmp22_)) {
				break;
			}
			_tmp23_ = _term_list;
			_tmp24_ = gee_list_get (_tmp23_, _term_index);
			term = (GearySearchQueryTerm*) _tmp24_;
			_tmp25_ = term;
			_tmp26_ = geary_search_query_term_get_is_negated (_tmp25_);
			_tmp27_ = _tmp26_;
			if (_tmp27_) {
				gint _tmp28_ = 0;
				GearySearchQueryTerm* _tmp29_;
				_tmp29_ = term;
				_tmp28_ = geary_fts_search_query_sql_bind_term_condition (self, sql, _tmp29_, next_index, &_inner_error0_);
				if (G_UNLIKELY (_inner_error0_ != NULL)) {
					if (_inner_error0_->domain == GEARY_DATABASE_ERROR) {
						gint _tmp30_ = -1;
						g_propagate_error (error, _inner_error0_);
						_g_object_unref0 (term);
						return _tmp30_;
					} else {
						gint _tmp31_ = -1;
						_g_object_unref0 (term);
						g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
						g_clear_error (&_inner_error0_);
						return _tmp31_;
					}
				}
				next_index = _tmp28_;
			}
			_g_object_unref0 (term);
		}
	}
	result = next_index;
	return result;
}

static inline gint
geary_fts_search_query_sql_bind_term_condition (GearyFtsSearchQuery* self,
                                                GearyDbStatement* sql,
                                                GearySearchQueryTerm* term,
                                                gint index,
                                                GError** error)
{
	gint next_index = 0;
	GType type = 0UL;
	GError* _inner_error0_ = NULL;
	gint result;
	g_return_val_if_fail (GEARY_IS_FTS_SEARCH_QUERY (self), 0);
	g_return_val_if_fail (GEARY_DB_IS_STATEMENT (sql), 0);
	g_return_val_if_fail (GEARY_SEARCH_QUERY_IS_TERM (term), 0);
	next_index = index;
	type = G_TYPE_FROM_INSTANCE (G_TYPE_CHECK_INSTANCE_CAST (term, G_TYPE_OBJECT, GObject));
	if (type == GEARY_SEARCH_QUERY_TYPE_EMAIL_TEXT_TERM) {
		GearySearchQueryEmailTextTerm* text = NULL;
		GearySearchQueryEmailTextTerm* _tmp0_;
		GeeList* stemmed_terms = NULL;
		GearySearchQueryEmailTextTerm* _tmp1_;
		gconstpointer _tmp2_;
		GeeList* _tmp3_;
		_tmp0_ = _g_object_ref0 (G_TYPE_CHECK_INSTANCE_CAST (term, GEARY_SEARCH_QUERY_TYPE_EMAIL_TEXT_TERM, GearySearchQueryEmailTextTerm));
		text = _tmp0_;
		_tmp1_ = text;
		_tmp2_ = g_object_get_data (G_TYPE_CHECK_INSTANCE_CAST (_tmp1_, G_TYPE_OBJECT, GObject), GEARY_FTS_SEARCH_QUERY_EMAIL_TEXT_STEMMED_TERMS);
		_tmp3_ = _g_object_ref0 ((GeeList*) _tmp2_);
		stemmed_terms = _tmp3_;
		{
			gint i = 0;
			i = 0;
			{
				gboolean _tmp4_ = FALSE;
				_tmp4_ = TRUE;
				while (TRUE) {
					GearySearchQueryEmailTextTerm* _tmp6_;
					GeeList* _tmp7_;
					GeeList* _tmp8_;
					gint _tmp9_;
					gint _tmp10_;
					gint _tmp11_;
					GearySearchQueryEmailTextTerm* _tmp12_;
					GeeList* _tmp13_;
					GeeList* _tmp14_;
					gint _tmp15_;
					gpointer _tmp16_;
					gchar* _tmp17_;
					GearyDbStatement* _tmp18_;
					GearyDbStatement* _tmp19_;
					gboolean _tmp22_ = FALSE;
					GeeList* _tmp23_;
					if (!_tmp4_) {
						gint _tmp5_;
						_tmp5_ = i;
						i = _tmp5_ + 1;
					}
					_tmp4_ = FALSE;
					_tmp6_ = text;
					_tmp7_ = geary_search_query_email_text_term_get_terms (_tmp6_);
					_tmp8_ = _tmp7_;
					_tmp9_ = gee_collection_get_size (G_TYPE_CHECK_INSTANCE_CAST (_tmp8_, GEE_TYPE_COLLECTION, GeeCollection));
					_tmp10_ = _tmp9_;
					if (!(i < _tmp10_)) {
						break;
					}
					_tmp11_ = next_index;
					next_index = _tmp11_ + 1;
					_tmp12_ = text;
					_tmp13_ = geary_search_query_email_text_term_get_terms (_tmp12_);
					_tmp14_ = _tmp13_;
					_tmp15_ = i;
					_tmp16_ = gee_list_get (_tmp14_, _tmp15_);
					_tmp17_ = (gchar*) _tmp16_;
					_tmp18_ = geary_db_statement_bind_string (sql, _tmp11_, _tmp17_, &_inner_error0_);
					_tmp19_ = _tmp18_;
					_g_object_unref0 (_tmp19_);
					_g_free0 (_tmp17_);
					if (G_UNLIKELY (_inner_error0_ != NULL)) {
						if (_inner_error0_->domain == GEARY_DATABASE_ERROR) {
							gint _tmp20_ = -1;
							g_propagate_error (error, _inner_error0_);
							_g_object_unref0 (stemmed_terms);
							_g_object_unref0 (text);
							return _tmp20_;
						} else {
							gint _tmp21_ = -1;
							_g_object_unref0 (stemmed_terms);
							_g_object_unref0 (text);
							g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
							g_clear_error (&_inner_error0_);
							return _tmp21_;
						}
					}
					_tmp23_ = stemmed_terms;
					if (_tmp23_ != NULL) {
						GeeList* _tmp24_;
						gpointer _tmp25_;
						gchar* _tmp26_;
						_tmp24_ = stemmed_terms;
						_tmp25_ = gee_list_get (_tmp24_, i);
						_tmp26_ = (gchar*) _tmp25_;
						_tmp22_ = _tmp26_ != NULL;
						_g_free0 (_tmp26_);
					} else {
						_tmp22_ = FALSE;
					}
					if (_tmp22_) {
						gint _tmp27_;
						GeeList* _tmp28_;
						gint _tmp29_;
						gpointer _tmp30_;
						gchar* _tmp31_;
						GearyDbStatement* _tmp32_;
						GearyDbStatement* _tmp33_;
						_tmp27_ = next_index;
						next_index = _tmp27_ + 1;
						_tmp28_ = stemmed_terms;
						_tmp29_ = i;
						_tmp30_ = gee_list_get (_tmp28_, _tmp29_);
						_tmp31_ = (gchar*) _tmp30_;
						_tmp32_ = geary_db_statement_bind_string (sql, _tmp27_, _tmp31_, &_inner_error0_);
						_tmp33_ = _tmp32_;
						_g_object_unref0 (_tmp33_);
						_g_free0 (_tmp31_);
						if (G_UNLIKELY (_inner_error0_ != NULL)) {
							if (_inner_error0_->domain == GEARY_DATABASE_ERROR) {
								gint _tmp34_ = -1;
								g_propagate_error (error, _inner_error0_);
								_g_object_unref0 (stemmed_terms);
								_g_object_unref0 (text);
								return _tmp34_;
							} else {
								gint _tmp35_ = -1;
								_g_object_unref0 (stemmed_terms);
								_g_object_unref0 (text);
								g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
								g_clear_error (&_inner_error0_);
								return _tmp35_;
							}
						}
					}
				}
			}
		}
		_g_object_unref0 (stemmed_terms);
		_g_object_unref0 (text);
	} else {
		if (type == GEARY_SEARCH_QUERY_TYPE_EMAIL_FLAG_TERM) {
			GearySearchQueryEmailFlagTerm* flag = NULL;
			GearySearchQueryEmailFlagTerm* _tmp36_;
			gint _tmp37_;
			GearySearchQueryEmailFlagTerm* _tmp38_;
			GearyNamedFlag* _tmp39_;
			GearyNamedFlag* _tmp40_;
			gchar* _tmp41_;
			gchar* _tmp42_;
			GearyDbStatement* _tmp43_;
			GearyDbStatement* _tmp44_;
			_tmp36_ = _g_object_ref0 (G_TYPE_CHECK_INSTANCE_CAST (term, GEARY_SEARCH_QUERY_TYPE_EMAIL_FLAG_TERM, GearySearchQueryEmailFlagTerm));
			flag = _tmp36_;
			_tmp37_ = next_index;
			next_index = _tmp37_ + 1;
			_tmp38_ = flag;
			_tmp39_ = geary_search_query_email_flag_term_get_value (_tmp38_);
			_tmp40_ = _tmp39_;
			_tmp41_ = geary_named_flag_serialise (_tmp40_);
			_tmp42_ = _tmp41_;
			_tmp43_ = geary_db_statement_bind_string (sql, _tmp37_, _tmp42_, &_inner_error0_);
			_tmp44_ = _tmp43_;
			_g_object_unref0 (_tmp44_);
			_g_free0 (_tmp42_);
			if (G_UNLIKELY (_inner_error0_ != NULL)) {
				if (_inner_error0_->domain == GEARY_DATABASE_ERROR) {
					gint _tmp45_ = -1;
					g_propagate_error (error, _inner_error0_);
					_g_object_unref0 (flag);
					return _tmp45_;
				} else {
					gint _tmp46_ = -1;
					_g_object_unref0 (flag);
					g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
					g_clear_error (&_inner_error0_);
					return _tmp46_;
				}
			}
			_g_object_unref0 (flag);
		}
	}
	result = next_index;
	return result;
}

static void
geary_fts_search_query_class_init (GearyFtsSearchQueryClass * klass,
                                   gpointer klass_data)
{
	geary_fts_search_query_parent_class = g_type_class_peek_parent (klass);
	g_type_class_adjust_private_offset (klass, &GearyFtsSearchQuery_private_offset);
	G_OBJECT_CLASS (klass)->get_property = _vala_geary_fts_search_query_get_property;
	G_OBJECT_CLASS (klass)->set_property = _vala_geary_fts_search_query_set_property;
	G_OBJECT_CLASS (klass)->finalize = geary_fts_search_query_finalize;
	g_object_class_install_property (G_OBJECT_CLASS (klass), GEARY_FTS_SEARCH_QUERY_HAS_STEMMED_TERMS_PROPERTY, geary_fts_search_query_properties[GEARY_FTS_SEARCH_QUERY_HAS_STEMMED_TERMS_PROPERTY] = g_param_spec_boolean ("has-stemmed-terms", "has-stemmed-terms", "has-stemmed-terms", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
}

static void
geary_fts_search_query_instance_init (GearyFtsSearchQuery * self,
                                      gpointer klass)
{
	self->priv = geary_fts_search_query_get_instance_private (self);
	self->priv->_has_stemmed_terms = FALSE;
	self->priv->is_all_negated = TRUE;
}

static void
geary_fts_search_query_finalize (GObject * obj)
{
	GearyFtsSearchQuery * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, GEARY_TYPE_FTS_SEARCH_QUERY, GearyFtsSearchQuery);
	G_OBJECT_CLASS (geary_fts_search_query_parent_class)->finalize (obj);
}

/**
 * A search query implementation that provides full-text search.
 */
 G_GNUC_NO_INLINE static GType
geary_fts_search_query_get_type_once (void)
{
	static const GTypeInfo g_define_type_info = { sizeof (GearyFtsSearchQueryClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) geary_fts_search_query_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (GearyFtsSearchQuery), 0, (GInstanceInitFunc) geary_fts_search_query_instance_init, NULL };
	GType geary_fts_search_query_type_id;
	geary_fts_search_query_type_id = g_type_register_static (GEARY_TYPE_SEARCH_QUERY, "GearyFtsSearchQuery", &g_define_type_info, 0);
	GearyFtsSearchQuery_private_offset = g_type_add_instance_private (geary_fts_search_query_type_id, sizeof (GearyFtsSearchQueryPrivate));
	return geary_fts_search_query_type_id;
}

GType
geary_fts_search_query_get_type (void)
{
	static gsize geary_fts_search_query_type_id__once = 0;
	if (g_once_init_enter (&geary_fts_search_query_type_id__once)) {
		GType geary_fts_search_query_type_id;
		geary_fts_search_query_type_id = geary_fts_search_query_get_type_once ();
		g_once_init_leave (&geary_fts_search_query_type_id__once, geary_fts_search_query_type_id);
	}
	return geary_fts_search_query_type_id__once;
}

static void
_vala_geary_fts_search_query_get_property (GObject * object,
                                           guint property_id,
                                           GValue * value,
                                           GParamSpec * pspec)
{
	GearyFtsSearchQuery * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (object, GEARY_TYPE_FTS_SEARCH_QUERY, GearyFtsSearchQuery);
	switch (property_id) {
		case GEARY_FTS_SEARCH_QUERY_HAS_STEMMED_TERMS_PROPERTY:
		g_value_set_boolean (value, geary_fts_search_query_get_has_stemmed_terms (self));
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

static void
_vala_geary_fts_search_query_set_property (GObject * object,
                                           guint property_id,
                                           const GValue * value,
                                           GParamSpec * pspec)
{
	GearyFtsSearchQuery * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (object, GEARY_TYPE_FTS_SEARCH_QUERY, GearyFtsSearchQuery);
	switch (property_id) {
		case GEARY_FTS_SEARCH_QUERY_HAS_STEMMED_TERMS_PROPERTY:
		geary_fts_search_query_set_has_stemmed_terms (self, g_value_get_boolean (value));
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

