/* * Copyright (C) 2012 - Juan Ferrer Toribio * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "sql-select.h" #include "sql-field.h" /** * SECTION: sql-select * @Short_description: an SQL SELECT statement * @Title: SqlSelect * * This object represents a SELECT SQL statement **/ typedef struct { SqlExpr * expr; gchar * alias; } SqlSelectAlias; typedef struct { SqlExpr * expr; SqlOrderWay way; } SqlOrder; G_DEFINE_TYPE (SqlSelect, sql_select, SQL_TYPE_DML); SqlSelect * sql_select_new () { return g_object_new (SQL_TYPE_SELECT, NULL); } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Private /* static const char * SQL_SELECT_TYPE[] = { NULL ,"UNION ALL" ,"UNION ANY" ,"INTERSECT" ,"EXCEPT" }; */ static void sql_select_render_order (SqlOrder * order, SqlRender * render) { sql_render_add_object (render, order->expr); if (order->way == SQL_ORDER_DESC) sql_render_add_token (render, "DESC"); } static void sql_select_render (SqlSelect * obj, SqlRender * render) { if (obj->alias) { GSList * n; sql_render_add_token (render, "SELECT"); for (n = obj->expr; n; n = n->next) { GSList * l; sql_render_add_object (render, n->data); for (l = obj->alias; l; l = l->next) if (((SqlSelectAlias *) l->data)->expr == n->data) { sql_render_add_identifier (render, ((SqlSelectAlias *) l->data)->alias); } if (n->next) sql_render_append (render, " ,"); } } else sql_render_add_list (render, T, "SELECT", obj->expr, ","); sql_render_add_list (render, F, "FROM", SQL_DML (obj)->target, ","); if (SQL_DML (obj)->target) { sql_render_add_item (render, F, "WHERE", SQL_DML (obj)->where); sql_render_add_list (render, F, "GROUP BY", obj->group, ","); sql_render_add_item (render, F, "HAVING", obj->having); sql_render_add_list_with_func (render, F, "ORDER", obj->order, ",", (SqlRenderFunc) sql_select_render_order); if (obj->limit_count) sql_render_printf (render, "LIMIT %u OFFSET %u" ,obj->limit_count ,obj->limit_offset ); } } static void sql_order_free (SqlOrder * obj) { g_object_unref (obj->expr); g_free (obj); } static void sql_select_alias_free (SqlSelectAlias * obj) { g_free (obj->alias); g_free (obj); } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Public void sql_select_add_expr (SqlSelect * obj, SqlExpr * expr) { g_return_if_fail (SQL_IS_SELECT (obj)); g_return_if_fail (SQL_IS_EXPR (expr)); obj->expr = g_slist_append (obj->expr, g_object_ref_sink (expr)); } void sql_select_set_alias (SqlSelect * obj, SqlExpr * expr, const gchar * alias) { GSList * list; g_return_if_fail (SQL_IS_SELECT (obj)); list = g_slist_find (obj->expr, expr); if (list) { SqlSelectAlias * as = g_new (SqlSelectAlias, 1); as->alias = g_strdup (alias); as->expr = expr; obj->alias = g_slist_append (obj->alias, as); } } /* * Return the alias of a field and if it's an unaliased SqlField, its name, * otherwise returns NULL (uses include of sql-field.h) */ gchar * sql_select_get_column_name (SqlSelect * obj, SqlExpr * expr) { gboolean listed = FALSE; GSList * n; g_return_val_if_fail (SQL_IS_SELECT (obj), NULL); g_return_val_if_fail (SQL_IS_EXPR (expr), NULL); for (n = obj->expr; n; n = n->next) if (expr == n->data) { listed = TRUE; break; } if (listed) for (n = obj->alias; n; n = n->next) { SqlSelectAlias * as = n->data; if (expr == as->expr) return g_strdup (as->alias); } if (SQL_IS_FIELD (expr)) { gchar * name; g_object_get (expr, "name", &name, NULL); return name; } return NULL; } void sql_select_add_group (SqlSelect * obj, SqlExpr * expr) { g_return_if_fail (SQL_IS_SELECT (obj)); g_return_if_fail (SQL_IS_EXPR (expr)); obj->group = g_slist_append (obj->group, g_object_ref_sink (expr)); } void sql_select_set_having (SqlSelect * obj, SqlExpr * expr) { g_return_if_fail (SQL_IS_SELECT (obj)); g_return_if_fail (SQL_IS_EXPR (expr)); g_clear_object (&obj->having); obj->having = g_object_ref_sink (expr); } void sql_select_add_order (SqlSelect * obj, SqlExpr * expr, SqlOrderWay way) { g_return_if_fail (SQL_IS_SELECT (obj)); g_return_if_fail (SQL_IS_EXPR (expr)); SqlOrder * order = g_new (SqlOrder, 1); order->expr = g_object_ref_sink (expr); order->way = way; obj->order = g_slist_append (obj->order, order); } void sql_select_set_distinct (SqlSelect * obj, gboolean distinct) { g_return_if_fail (SQL_IS_SELECT (obj)); obj->distinct = distinct; } void sql_select_set_limit (SqlSelect * obj, guint count, guint offset) { g_return_if_fail (SQL_IS_SELECT (obj)); obj->limit_count = count; obj->limit_offset = offset; } void sql_select_set_next (SqlSelect * obj, SqlSelect * next, SqlSelectType type) { g_return_if_fail (SQL_IS_SELECT (obj)); g_return_if_fail (SQL_IS_SELECT (next) || !next); g_clear_object (&obj->next); if (next) { obj->next = g_object_ref (next); obj->type = type; } else obj->type = SQL_SELECT_NONE; } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Properties enum { PROP_DISTINCT = 1 ,PROP_LIMIT_COUNT ,PROP_LIMIT_OFFSET ,PROP_HAVING ,PROP_TYPE ,PROP_NEXT }; static void sql_select_set_property (SqlSelect * obj, guint id, const GValue * value, GParamSpec * pspec) { switch (id) { case PROP_DISTINCT: obj->distinct = g_value_get_boolean (value); break; case PROP_LIMIT_COUNT: obj->limit_count = g_value_get_uint (value); break; case PROP_LIMIT_OFFSET: obj->limit_offset = g_value_get_uint (value); break; case PROP_HAVING: sql_select_set_having (obj, g_value_get_object (value)); break; case PROP_TYPE: obj->type = g_value_get_int (value); break; case PROP_NEXT: sql_select_set_next (obj, g_value_get_object (value), obj->type); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, id, pspec); } } static void sql_select_get_property (SqlSelect * obj, guint id, GValue * value, GParamSpec * pspec) { switch (id) { case PROP_DISTINCT: g_value_set_boolean (value, obj->distinct); break; case PROP_LIMIT_COUNT: g_value_set_uint (value, obj->limit_count); break; case PROP_LIMIT_OFFSET: g_value_set_uint (value, obj->limit_offset); break; case PROP_HAVING: g_value_set_object (value, obj->having); break; case PROP_TYPE: g_value_set_int (value, obj->type); break; case PROP_NEXT: g_value_set_object (value, obj->next); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, id, pspec); } } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Class static void sql_select_init (SqlSelect * obj) { obj->distinct = FALSE; obj->expr = NULL; obj->alias = NULL; obj->group = NULL; obj->having = NULL; obj->order = NULL; obj->next = NULL; obj->type = SQL_SELECT_NONE; } static void sql_select_finalize (SqlSelect * obj) { g_clear_object (&obj->having); g_clear_object (&obj->next); g_slist_free_full (obj->expr, g_object_unref); g_slist_free_full (obj->group, g_object_unref); g_slist_free_full (obj->alias, (GFreeFunc) sql_select_alias_free); g_slist_free_full (obj->order, (GFreeFunc) sql_order_free); G_OBJECT_CLASS (sql_select_parent_class)->finalize (G_OBJECT (obj)); } static void sql_select_class_init (SqlSelectClass * k) { GObjectClass * klass = G_OBJECT_CLASS (k); klass->finalize = (GObjectFinalizeFunc) sql_select_finalize; klass->set_property = (GObjectSetPropertyFunc) sql_select_set_property; klass->get_property = (GObjectGetPropertyFunc) sql_select_get_property; SQL_OBJECT_CLASS (klass)->render = (SqlRenderFunc) sql_select_render; g_object_class_install_property (klass, PROP_LIMIT_COUNT, g_param_spec_boolean ("distinct" ,"Distinct" ,"Determines if the #SqlSelect uses the DISTINCT clause" ,FALSE, G_PARAM_READWRITE )); g_object_class_install_property (klass, PROP_LIMIT_COUNT, g_param_spec_uint ("limit-count" ,"Limit count" ,"The COUNT field of the LIMIT clause" ,0, G_MAXUINT, 0, G_PARAM_READWRITE )); g_object_class_install_property (klass, PROP_LIMIT_OFFSET, g_param_spec_uint ("limit-offset" ,"Limit offset" ,"The OFFSET field of the LIMIT clause" ,0, G_MAXUINT, 0, G_PARAM_READWRITE )); g_object_class_install_property (klass, PROP_HAVING, g_param_spec_object ("having" ,"Having" ,"The HAVING clause" ,SQL_TYPE_EXPR, G_PARAM_READWRITE )); g_object_class_install_property (klass, PROP_TYPE, g_param_spec_int ("type" ,"Type" ,"One of the possible options of #SqlSelectType" ,0, SQL_SELECT_COUNT - 1, 0, G_PARAM_READWRITE )); g_object_class_install_property (klass, PROP_NEXT, g_param_spec_object ("next" ,"Next" ,"The next #SqlSelect in case of a statement with more than one" ,SQL_TYPE_SELECT, G_PARAM_READWRITE )); }