// midgard_query_constraint
static PHP_METHOD(midgard_query_constraint, __construct)
{
	char *operator = NULL;
	int operator_len = 0;
	zval *z_property = NULL;
	zval *z_holder = NULL;
	zval *z_storage = NULL;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OsO|O",
			&z_property, php_midgard_query_property_class,
			&operator, &operator_len,
			&z_holder, php_midgard_query_holder_class,
			&z_storage, php_midgard_query_storage_class
			) == FAILURE
	) {
		return;
	}

	MidgardQueryProperty *property = MIDGARD_QUERY_PROPERTY(__php_gobject_ptr(z_property));
	MidgardQueryHolder   *holder   = MIDGARD_QUERY_HOLDER(__php_gobject_ptr(z_holder));
	MidgardQueryStorage  *storage  = NULL; 

	if (z_storage) {
		storage = MIDGARD_QUERY_STORAGE(__php_gobject_ptr(z_storage));
	}

	MidgardQueryConstraint *constraint = midgard_query_constraint_new(property, operator, holder, storage);

	if (!constraint) {
		zend_throw_exception_ex(ce_midgard_error_exception, 0 TSRMLS_CC, "Failed to create constraint");
		return;
	}

	MGD_PHP_SET_GOBJECT(getThis(), constraint);
}
static PHP_METHOD(midgard_sql_query_column, __construct)
{
	zval *z_qprop = NULL;
	char *name = NULL;
	char *qualifier = NULL;
	int name_length = 0;
	int qualifier_length = 0;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|s",
				&z_qprop, php_midgard_query_property_class,
				&qualifier, &qualifier_length, 
				&name, &name_length
				) == FAILURE
	   ) {
		return;
	}

	MidgardQueryProperty *queryproperty = MIDGARD_QUERY_PROPERTY(__php_gobject_ptr(z_qprop));
	MidgardSqlQueryColumn *column = midgard_sql_query_column_new(queryproperty, qualifier, name);
	if (!column) {
		zend_throw_exception_ex(ce_midgard_error_exception, 0 TSRMLS_CC, "Failed to create SqlQueryColumn");
		return;
	}
	MGD_PHP_SET_GOBJECT(getThis(), column);
}
/* Validable iface */
static void
_midgard_query_property_validable_iface_validate (MidgardValidable *iface, GError **error)
{
	g_return_if_fail (iface != NULL);
	MidgardQueryProperty *self = MIDGARD_QUERY_PROPERTY (iface);
	self->priv->is_valid = FALSE;
	MidgardQueryStorage *storage = self->priv->storage;

	if (!G_IS_VALUE (&self->priv->value) ||  !G_VALUE_HOLDS_STRING (&self->priv->value)) {
		g_set_error (error, MIDGARD_VALIDATION_ERROR, MIDGARD_VALIDATION_ERROR_VALUE_INVALID,
				"Invalid property's value type");
		return;
	}

	/* There's no class context without storage. We have no access to executor,
	 * so we assume property is valid. */
	if (!storage)
		return;

	/* We do not check if storage is valid */
	if (!storage->priv->classname)
		return;

	GObjectClass *klass = g_type_class_peek (g_type_from_name (storage->priv->classname));
	if (!klass)
		return;

	const gchar *property_name = g_value_get_string (&self->priv->value);
	GParamSpec *pspec = g_object_class_find_property (klass, property_name);
	if (!pspec) {
		g_set_error (error, MIDGARD_VALIDATION_ERROR, MIDGARD_VALIDATION_ERROR_NAME_INVALID,
				"Property '%s' is not registered for '%s' class.",
				property_name,
				G_OBJECT_CLASS_NAME (klass));
		return;
	}

	MIDGARD_QUERY_PROPERTY (self)->priv->is_valid = TRUE;
	return;
}
static void
_midgard_query_property_finalize (GObject *object)
{
	MidgardQueryProperty *self = MIDGARD_QUERY_PROPERTY (object);

	if (self->priv && G_IS_VALUE (&self->priv->value))
		g_value_unset (&self->priv->value);

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

        parent_class->finalize (object);
}
gboolean
_midgard_query_select_add_join (MidgardQueryExecutor *self, const gchar *join_type, 
		MidgardQueryHolder *left_holder, MidgardQueryHolder *right_holder)
{
	g_return_val_if_fail (self != NULL, FALSE);
	g_return_val_if_fail (join_type != NULL, FALSE);
	g_return_val_if_fail (left_holder != NULL, FALSE);
	g_return_val_if_fail (right_holder != NULL, FALSE);

	MidgardQueryProperty *left_property = MIDGARD_QUERY_PROPERTY (left_holder);
	g_return_val_if_fail (MIDGARD_IS_QUERY_PROPERTY (left_property), FALSE);
	MidgardQueryProperty *right_property = MIDGARD_QUERY_PROPERTY (right_holder);
	g_return_val_if_fail (MIDGARD_IS_QUERY_PROPERTY (right_property), FALSE);

	/* validate join type */
	GdaSqlSelectJoinType join_type_id;
	if (!__query_join_type_is_valid (join_type, &join_type_id)) 
		return FALSE;

	/* MidgardQueryStorage *left_storage = left_property->priv->storage; */
	MidgardQueryStorage *right_storage = right_property->priv->storage;

	/* We can not join the same table adding new implicit table alias */
	if (!right_storage) {
		g_warning ("Can not add join. Right property storage is NULL. ");
	       return FALSE;	
	}

	qsj *_sj = g_new (qsj, 1);
	_sj->left_property = g_object_ref (left_property);
	_sj->right_property = g_object_ref (right_property);

	_sj->join_type = join_type_id;

	self->priv->joins = g_slist_append (self->priv->joins, _sj);

	return TRUE;
}
static PHP_METHOD(midgard_query_constraint, set_property)
{
	zval *z_property = NULL;

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

	MidgardQueryConstraint *constraint = MIDGARD_QUERY_CONSTRAINT(__php_gobject_ptr(getThis()));
	MidgardQueryProperty *property = MIDGARD_QUERY_PROPERTY(__php_gobject_ptr(z_property));

	zend_bool result = midgard_query_constraint_set_property(constraint, property);

	RETURN_BOOL(result);
}
gboolean
_midgard_query_property_validable_iface_is_valid (MidgardValidable *self)
{
	g_return_val_if_fail (self != NULL, FALSE);
	return MIDGARD_QUERY_PROPERTY (self)->priv->is_valid;
}