static void
_midgard_query_constraint_group_dispose (GObject *object)
{
	MidgardQueryConstraintGroup *self = MIDGARD_QUERY_CONSTRAINT_GROUP (object);
	GSList *self_constraints = MIDGARD_QUERY_CONSTRAINT_GROUP (self)->priv->constraints;
	GSList *l = NULL;
	for (l = self_constraints; l != NULL; l = l->next) {
		if (l->data && G_IS_OBJECT (l->data)) {
			g_object_unref(l->data);
			l->data = NULL;
		}
	}
	parent_class->dispose (object);
}
void
_midgard_query_group_add_conditions_to_statement (MidgardQueryExecutor *executor, MidgardQueryConstraintSimple *self, 
		GdaSqlStatement *stmt, GdaSqlExpr *where_expr_node, GError **error)
{	
	guint n_objects;
	guint i;
	MidgardQueryConstraintSimple **constraints = 
		midgard_query_constraint_simple_list_constraints (MIDGARD_QUERY_CONSTRAINT_SIMPLE (self), &n_objects);
	if (!constraints)
		return;

	GdaSqlStatementSelect *select = stmt->contents;
	GdaSqlExpr *top_where = NULL, *where;
	GdaSqlOperation *top_operation, *operation;	
	
	/* Create base top expression and operation */
	if (!select->where_cond) {
		top_where = gda_sql_expr_new (GDA_SQL_ANY_PART (select));
		top_operation = gda_sql_operation_new (GDA_SQL_ANY_PART (top_where));
		top_operation->operator_type = MIDGARD_QUERY_CONSTRAINT_GROUP (self)->priv->op_type;
		top_where->cond = top_operation;
	     	gda_sql_statement_select_take_where_cond (stmt, top_where);	
	} else if (where_expr_node) {
		/* This is nested groups case: '... AND (f2=1 OR f2=2)...' */
		where = where_expr_node;
		operation = where->cond;
		top_where = gda_sql_expr_new (GDA_SQL_ANY_PART (operation));
		top_operation = gda_sql_operation_new (GDA_SQL_ANY_PART (where_expr_node));
		top_operation->operator_type = MIDGARD_QUERY_CONSTRAINT_GROUP (self)->priv->op_type;
		top_where->cond = top_operation;
		operation->operands = g_slist_append (operation->operands, top_where);
	}

	for (i = 0; i < n_objects; i++) {

		GError *err = NULL;
		MIDGARD_QUERY_CONSTRAINT_SIMPLE_GET_INTERFACE (constraints[i])->priv->add_conditions_to_statement (executor, MIDGARD_QUERY_CONSTRAINT_SIMPLE (constraints[i]), stmt, top_where, &err);
		if (err)
			g_propagate_error (error, err);
	}

	g_free (constraints);
}
static PHP_METHOD(midgard_query_constraint_group, set_type)
{
	char *type = NULL;
	int type_len = 0;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &type, &type_len) == FAILURE) {
		return;
	}

	MidgardQueryConstraintGroup *constraint_group = MIDGARD_QUERY_CONSTRAINT_GROUP(__php_gobject_ptr(getThis()));
	zend_bool result = midgard_query_constraint_group_set_group_type(constraint_group, type);

	RETURN_BOOL(result);
}
static PHP_METHOD(midgard_query_constraint_group, get_type)
{
	if (zend_parse_parameters_none() == FAILURE)
		return;

	MidgardQueryConstraintGroup *constraint_group = MIDGARD_QUERY_CONSTRAINT_GROUP(__php_gobject_ptr(getThis()));
	const gchar *type = midgard_query_constraint_group_get_group_type(constraint_group);

	if (!type) {
		return;
	}

	RETURN_STRING(type, 1);
}
static PHP_METHOD(midgard_query_constraint_group, add_constraint)
{
	zval *z_constraint = NULL;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &z_constraint, php_midgard_query_constraint_simple_class) == FAILURE) {
		return;
	}

	MidgardQueryConstraintGroup *constraint_group = MIDGARD_QUERY_CONSTRAINT_GROUP(__php_gobject_ptr(getThis()));
	MidgardQueryConstraintSimple *constraint = MIDGARD_QUERY_CONSTRAINT_SIMPLE(__php_gobject_ptr(z_constraint));

	zend_bool result = midgard_query_constraint_group_add_constraint(constraint_group, constraint, NULL);

	RETURN_BOOL(result);
}
static void
_midgard_query_constraint_group_finalize (GObject *object)
{
	MidgardQueryConstraintGroup *self = MIDGARD_QUERY_CONSTRAINT_GROUP (object);
	
	g_free (self->priv->type);
	self->priv->type = NULL;

	if (self->priv->constraints)
		g_slist_free (self->priv->constraints);
	self->priv->constraints = NULL; 

	g_free (self->priv);
	self->priv = NULL;

	parent_class->finalize (object);
}
/* Validable iface */
static void
_midgard_query_constraint_group_validable_iface_validate (MidgardValidable *iface, GError **error)
{
	g_return_if_fail (iface != NULL);
	MidgardQueryConstraintGroup *self = MIDGARD_QUERY_CONSTRAINT_GROUP (iface);
	self->priv->is_valid = FALSE;

	/* group type */
	if (self->priv->op_type == -1) {
		g_set_error (error, MIDGARD_VALIDATION_ERROR, MIDGARD_VALIDATION_ERROR_TYPE_INVALID,
				"Invalid group operator type");
		return;
	}

	/* constraints */
	if (!self->priv->constraints) {
		g_set_error (error, MIDGARD_VALIDATION_ERROR, MIDGARD_VALIDATION_ERROR_ELEMENT_INVALID,
				"Constraint group doesn't hold any constraints");
		return;
	}

	self->priv->is_valid = TRUE;
	return;
}
gboolean
_midgard_query_constraint_group_validable_iface_is_valid (MidgardValidable *self)
{
	g_return_val_if_fail (self != NULL, FALSE);
	return MIDGARD_QUERY_CONSTRAINT_GROUP (self)->priv->is_valid;
}