1 /*
2 * Copyright (C) 2008 - 2010 Murray Cumming <murrayc@murrayc.com>
3 * Copyright (C) 2008 - 2011 Vivien Malerba <malerba@gnome-db.org>
4 * Copyright (C) 2009 Bas Driessen <bas.driessen@xobas.com>
5 * Copyright (C) 2010 David King <davidk@openismus.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #include <libgda/gda-debug-macros.h>
24 #include <libgda/sql-parser/gda-statement-struct.h>
25 #include <libgda/sql-parser/gda-statement-struct-compound.h>
26 #include <libgda/sql-parser/gda-statement-struct-pspec.h>
27 #include <string.h>
28 #include <glib/gi18n-lib.h>
29
30 static gpointer gda_sql_statement_compound_new (void);
31 static gboolean gda_sql_statement_compound_check_structure (GdaSqlAnyPart *stmt, gpointer data, GError **error);
32
33 GdaSqlStatementContentsInfo compound_infos = {
34 GDA_SQL_STATEMENT_COMPOUND,
35 "COMPOUND",
36 gda_sql_statement_compound_new,
37 _gda_sql_statement_compound_free,
38 _gda_sql_statement_compound_copy,
39 _gda_sql_statement_compound_serialize,
40
41 gda_sql_statement_compound_check_structure,
42 NULL,
43 NULL,
44 NULL,
45 NULL,
46 NULL
47 };
48
49 GdaSqlStatementContentsInfo *
_gda_sql_statement_compound_get_infos(void)50 _gda_sql_statement_compound_get_infos (void)
51 {
52 return &compound_infos;
53 }
54
55 static gpointer
gda_sql_statement_compound_new(void)56 gda_sql_statement_compound_new (void)
57 {
58 GdaSqlStatementCompound *stmt;
59 stmt = g_new0 (GdaSqlStatementCompound, 1);
60 stmt->compound_type = -1;
61 GDA_SQL_ANY_PART (stmt)->type = GDA_SQL_ANY_STMT_COMPOUND;
62 return stmt;
63 }
64
65 void
_gda_sql_statement_compound_free(gpointer stmt)66 _gda_sql_statement_compound_free (gpointer stmt)
67 {
68 GdaSqlStatementCompound *compound = (GdaSqlStatementCompound *) stmt;
69
70 if (compound->stmt_list) {
71 g_slist_foreach (compound->stmt_list, (GFunc) gda_sql_statement_free, NULL);
72 g_slist_free (compound->stmt_list);
73 }
74 g_free (compound);
75 }
76
77 gpointer
_gda_sql_statement_compound_copy(gpointer src)78 _gda_sql_statement_compound_copy (gpointer src)
79 {
80 GdaSqlStatementCompound *dest;
81 GdaSqlStatementCompound *compound = (GdaSqlStatementCompound *) src;
82 GSList *list;
83
84 dest = gda_sql_statement_compound_new ();
85 dest->compound_type = compound->compound_type;
86 for (list = compound->stmt_list; list; list = list->next) {
87 GdaSqlStatement *sqlst;
88 sqlst = gda_sql_statement_copy ((GdaSqlStatement*) list->data);
89 gda_sql_any_part_set_parent (sqlst->contents, dest);
90 dest->stmt_list = g_slist_prepend (dest->stmt_list, sqlst);
91 }
92 dest->stmt_list = g_slist_reverse (dest->stmt_list);
93
94 return dest;
95 }
96
97 gchar *
_gda_sql_statement_compound_serialize(gpointer stmt)98 _gda_sql_statement_compound_serialize (gpointer stmt)
99 {
100 GString *string;
101 gchar *str;
102 GSList *list;
103 GdaSqlStatementCompound *compound = (GdaSqlStatementCompound *) stmt;
104
105 g_return_val_if_fail (stmt, NULL);
106
107 string = g_string_new ("\"contents\":{");
108 g_string_append (string, "\"compount_type\":");
109 switch (compound->compound_type) {
110 case GDA_SQL_STATEMENT_COMPOUND_UNION:
111 str = "UNION"; break;
112 case GDA_SQL_STATEMENT_COMPOUND_UNION_ALL:
113 str = "AUNION"; break;
114 case GDA_SQL_STATEMENT_COMPOUND_INTERSECT:
115 str = "INTERSECT"; break;
116 case GDA_SQL_STATEMENT_COMPOUND_INTERSECT_ALL:
117 str = "AINTERSECT"; break;
118 case GDA_SQL_STATEMENT_COMPOUND_EXCEPT:
119 str = "EXCEPT"; break;
120 case GDA_SQL_STATEMENT_COMPOUND_EXCEPT_ALL:
121 str = "AEXCEPT"; break;
122 default:
123 str = NULL;
124 g_assert_not_reached ();
125 }
126 g_string_append_printf (string, "\"%s\"", str);
127
128 if (compound->stmt_list) {
129 g_string_append (string, ",\"select_stmts\":[");
130 for (list = compound->stmt_list; list; list = list->next) {
131 if (list != compound->stmt_list)
132 g_string_append_c (string, ',');
133 str = gda_sql_statement_serialize ((GdaSqlStatement*) list->data);
134 g_string_append (string, str);
135 g_free (str);
136 }
137 g_string_append_c (string, ']');
138 }
139
140 g_string_append_c (string, '}');
141 str = string->str;
142 g_string_free (string, FALSE);
143 return str;
144 }
145
146 /**
147 * gda_sql_statement_compound_take_stmt
148 * @stmt: a #GdaSqlStatement pointer
149 * @s: a #GdaSqlStatement pointer
150 *
151 * Adds the @s sub-statement to the @stmt compound statement. @s's reference is transferred to
152 * @stmt (which means @stmt is then responsible for freeing it when no longer needed).
153 */
154 void
gda_sql_statement_compound_take_stmt(GdaSqlStatement * stmt,GdaSqlStatement * s)155 gda_sql_statement_compound_take_stmt (GdaSqlStatement *stmt, GdaSqlStatement *s)
156 {
157 GdaSqlStatementCompound *compound = (GdaSqlStatementCompound *) stmt->contents;
158
159 if (s->stmt_type == GDA_SQL_STATEMENT_COMPOUND) {
160 GdaSqlStatementCompound *scompound = (GdaSqlStatementCompound *) s->contents;
161 if (scompound->stmt_list) {
162 if (scompound->stmt_list->next) {
163 compound->stmt_list = g_slist_append (compound->stmt_list, s);
164 gda_sql_any_part_set_parent (s->contents, stmt);
165 }
166 else {
167 compound->stmt_list = g_slist_append (compound->stmt_list, scompound->stmt_list->data);
168 gda_sql_any_part_set_parent (((GdaSqlStatement*) scompound->stmt_list->data)->contents, stmt);
169 g_slist_free (scompound->stmt_list);
170 scompound->stmt_list = NULL;
171 gda_sql_statement_free (s);
172 }
173 }
174 else {
175 /* ignore @s */
176 gda_sql_statement_free (s);
177 return;
178 }
179 }
180 else {
181 compound->stmt_list = g_slist_append (compound->stmt_list, s);
182 gda_sql_any_part_set_parent (s->contents, stmt);
183 }
184 }
185
186 GdaSqlAnyPart *
_gda_sql_statement_compound_reduce(GdaSqlAnyPart * compound_or_select)187 _gda_sql_statement_compound_reduce (GdaSqlAnyPart *compound_or_select)
188 {
189 GdaSqlAnyPart *part;
190
191 part = compound_or_select;
192 if (part->type == GDA_SQL_ANY_STMT_COMPOUND) {
193 /* if only one child, then use that child instead */
194 GdaSqlStatementCompound *compound = (GdaSqlStatementCompound*) part;
195 if (compound->stmt_list && !compound->stmt_list->next) {
196 GdaSqlAnyPart *rpart;
197 GdaSqlStatement *substmt;
198 substmt = (GdaSqlStatement *) compound->stmt_list->data;
199
200 rpart = GDA_SQL_ANY_PART (substmt->contents);
201 substmt->contents = NULL;
202 gda_sql_statement_free (substmt);
203
204 g_slist_free (compound->stmt_list);
205 compound->stmt_list = NULL;
206 _gda_sql_statement_compound_free (compound);
207 part = _gda_sql_statement_compound_reduce (rpart);
208 }
209 }
210
211 return part;
212 }
213
214
215 /**
216 * gda_sql_statement_compound_set_type
217 * @stmt: a #GdaSqlStatement pointer
218 * @type: a #GdaSqlStatementCompoundType value
219 *
220 * Specifies @stmt's type of compound
221 */
222 void
gda_sql_statement_compound_set_type(GdaSqlStatement * stmt,GdaSqlStatementCompoundType type)223 gda_sql_statement_compound_set_type (GdaSqlStatement *stmt, GdaSqlStatementCompoundType type)
224 {
225 GdaSqlStatementCompound *compound = (GdaSqlStatementCompound *) stmt->contents;
226 compound->compound_type = type;
227 }
228
229 gint
_gda_sql_statement_compound_get_n_cols(GdaSqlStatementCompound * compound,GError ** error)230 _gda_sql_statement_compound_get_n_cols (GdaSqlStatementCompound *compound, GError **error)
231 {
232 if (!compound || !compound->stmt_list) {
233 g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
234 "%s", _("COMPOUND statement contains an undefined COMPOUND statement"));
235 return -1;
236 }
237
238 /* @compound's children */
239 GdaSqlStatement *sqlstmt = (GdaSqlStatement*) compound->stmt_list->data;
240 if (sqlstmt->stmt_type == GDA_SQL_STATEMENT_SELECT) {
241 if (!sqlstmt->contents) {
242 g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
243 "%s", _("COMPOUND statement contains an undefined SELECT statement"));
244 return -1;
245 }
246 return g_slist_length (((GdaSqlStatementSelect*) sqlstmt->contents)->expr_list);
247 }
248 else if (sqlstmt->stmt_type == GDA_SQL_STATEMENT_COMPOUND)
249 return _gda_sql_statement_compound_get_n_cols ((GdaSqlStatementCompound*) sqlstmt->contents, error);
250 else {
251 g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
252 "%s", _("COMPOUND statement contains a non SELECT statement"));
253 return -1;
254 }
255 }
256
257 static gboolean
gda_sql_statement_compound_check_structure(GdaSqlAnyPart * stmt,G_GNUC_UNUSED gpointer data,GError ** error)258 gda_sql_statement_compound_check_structure (GdaSqlAnyPart *stmt, G_GNUC_UNUSED gpointer data, GError **error)
259 {
260 GdaSqlStatementCompound *compound = (GdaSqlStatementCompound *) stmt;
261 gint nb_cols = -1;
262 GSList *list;
263
264 if (!compound->stmt_list) {
265 g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
266 "%s", _("COMPOUND statement does not contain any SELECT statement"));
267 return FALSE;
268 }
269
270 if (!compound->stmt_list->next) {
271 g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
272 "%s", _("COMPOUND statement only contains one SELECT statement"));
273 return FALSE;
274 }
275
276 for (list = compound->stmt_list; list; list = list->next) {
277 GdaSqlStatement *sqlstmt = (GdaSqlStatement*) list->data;
278 gint nb;
279 if (sqlstmt->stmt_type == GDA_SQL_STATEMENT_SELECT) {
280 if (!sqlstmt->contents) {
281 g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
282 "%s", _("COMPOUND statement contains an undefined SELECT statement"));
283 return FALSE;
284 }
285 nb = g_slist_length (((GdaSqlStatementSelect*) sqlstmt->contents)->expr_list);
286 }
287 else if (sqlstmt->stmt_type == GDA_SQL_STATEMENT_COMPOUND) {
288 nb = _gda_sql_statement_compound_get_n_cols ((GdaSqlStatementCompound*) sqlstmt->contents, error);
289 if (nb < 0)
290 return FALSE;
291 }
292 else {
293 g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
294 "%s", _("COMPOUND statement contains a non SELECT statement"));
295 return FALSE;
296 }
297
298 if (nb_cols == -1) {
299 nb_cols = nb;
300 if (nb == 0) {
301 g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
302 "%s", _("COMPOUND statement contains an empty SELECT statement"));
303 return FALSE;
304 }
305 }
306 else if (nb != nb_cols) {
307 g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
308 "%s", _("All statements in a COMPOUND must have the same number of columns"));
309 return FALSE;
310 }
311 }
312
313 return TRUE;
314 }
315