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-insert.h>
26 #include <libgda/sql-parser/gda-statement-struct-compound.h>
27 #include <libgda/sql-parser/gda-statement-struct-util.h>
28 #include <libgda/sql-parser/gda-statement-struct-pspec.h>
29 #include <string.h>
30 #include <glib/gi18n-lib.h>
31 
32 static gpointer  gda_sql_statement_insert_new (void);
33 static void      gda_sql_statement_insert_free (gpointer stmt);
34 static gpointer  gda_sql_statement_insert_copy (gpointer src);
35 static gchar    *gda_sql_statement_insert_serialize (gpointer stmt);
36 static gboolean  gda_sql_statement_insert_check_structure (GdaSqlAnyPart *stmt, gpointer data, GError **error);
37 
38 GdaSqlStatementContentsInfo insert_infos = {
39 	GDA_SQL_STATEMENT_INSERT,
40 	"INSERT",
41 	gda_sql_statement_insert_new,
42 	gda_sql_statement_insert_free,
43 	gda_sql_statement_insert_copy,
44 	gda_sql_statement_insert_serialize,
45 
46 	gda_sql_statement_insert_check_structure,
47 	NULL,
48 	NULL,
49 	NULL,
50 	NULL,
51 	NULL
52 };
53 
54 GdaSqlStatementContentsInfo *
_gda_sql_statement_insert_get_infos(void)55 _gda_sql_statement_insert_get_infos (void)
56 {
57 	return &insert_infos;
58 }
59 
60 static gpointer
gda_sql_statement_insert_new(void)61 gda_sql_statement_insert_new (void)
62 {
63 	GdaSqlStatementInsert *stmt;
64 	stmt = g_new0 (GdaSqlStatementInsert, 1);
65 	GDA_SQL_ANY_PART (stmt)->type = GDA_SQL_ANY_STMT_INSERT;
66 	return (gpointer) stmt;
67 }
68 
69 static void
gda_sql_statement_insert_free(gpointer stmt)70 gda_sql_statement_insert_free (gpointer stmt)
71 {
72 	GdaSqlStatementInsert *insert = (GdaSqlStatementInsert *) stmt;
73 	GSList *list;
74 	g_free (insert->on_conflict);
75 	gda_sql_table_free (insert->table);
76 	for (list = insert->values_list; list; list = list->next) {
77 		if (list->data) {
78 			g_slist_foreach ((GSList *) list->data, (GFunc) gda_sql_expr_free, NULL);
79 			g_slist_free ((GSList *) list->data);
80 		}
81 	}
82 	g_slist_free (insert->values_list);
83 
84 	g_slist_foreach (insert->fields_list, (GFunc) gda_sql_field_free, NULL);
85 	g_slist_free (insert->fields_list);
86 	if (insert->select) {
87 		if (GDA_SQL_ANY_PART (insert->select)->type == GDA_SQL_ANY_STMT_SELECT)
88 			_gda_sql_statement_select_free (insert->select);
89 		else if (GDA_SQL_ANY_PART (insert->select)->type == GDA_SQL_ANY_STMT_COMPOUND)
90 			_gda_sql_statement_compound_free (insert->select);
91 		else
92 			g_assert_not_reached ();
93 	}
94 
95 	g_free (insert);
96 }
97 
98 static gpointer
gda_sql_statement_insert_copy(gpointer src)99 gda_sql_statement_insert_copy (gpointer src)
100 {
101 	GdaSqlStatementInsert *dest;
102 	GSList *list;
103 	GdaSqlStatementInsert *insert = (GdaSqlStatementInsert *) src;
104 
105 	dest = gda_sql_statement_insert_new ();
106 	if (insert->on_conflict)
107 		dest->on_conflict = g_strdup (insert->on_conflict);
108 
109 	dest->table = gda_sql_table_copy (insert->table);
110 	gda_sql_any_part_set_parent (dest->table, dest);
111 
112 	for (list = insert->fields_list; list; list = list->next) {
113 		dest->fields_list = g_slist_prepend (dest->fields_list,
114 						     gda_sql_field_copy ((GdaSqlField*) list->data));
115 		gda_sql_any_part_set_parent (dest->fields_list->data, dest);
116 	}
117 	dest->fields_list = g_slist_reverse (dest->fields_list);
118 
119 	for (list = insert->values_list; list; list = list->next) {
120 		GSList *vlist, *clist = NULL;
121 		for (vlist = (GSList *) list->data; vlist; vlist = vlist->next) {
122 			clist = g_slist_prepend (clist,
123 						 gda_sql_expr_copy ((GdaSqlExpr*) vlist->data));
124 			gda_sql_any_part_set_parent (clist->data, dest);
125 		}
126 		dest->values_list = g_slist_append (dest->values_list, g_slist_reverse (clist));
127 	}
128 	if (insert->select) {
129 		if (GDA_SQL_ANY_PART (insert->select)->type == GDA_SQL_ANY_STMT_SELECT)
130 			dest->select = _gda_sql_statement_select_copy (insert->select);
131 		else if (GDA_SQL_ANY_PART (insert->select)->type == GDA_SQL_ANY_STMT_COMPOUND)
132 			dest->select = _gda_sql_statement_compound_copy (insert->select);
133 		else
134 			g_assert_not_reached ();
135 		gda_sql_any_part_set_parent (dest->select, dest);
136 	}
137 
138 	return dest;
139 }
140 
141 static gchar *
gda_sql_statement_insert_serialize(gpointer stmt)142 gda_sql_statement_insert_serialize (gpointer stmt)
143 {
144 	GString *string;
145 	gchar *str;
146 	GSList *list;
147 	GdaSqlStatementInsert *insert = (GdaSqlStatementInsert *) stmt;
148 
149 	g_return_val_if_fail (stmt, NULL);
150 
151 	string = g_string_new ("\"contents\":{");
152 
153 	/* table name */
154 	g_string_append (string, "\"table\":");
155 	str = gda_sql_table_serialize (insert->table);
156 	g_string_append (string, str);
157 	g_free (str);
158 
159 	/* fields */
160 	g_string_append (string, ",\"fields\":");
161 	if (insert->fields_list) {
162 		g_string_append_c (string, '[');
163 		for (list = insert->fields_list; list; list = list->next) {
164 			if (list != insert->fields_list)
165 				g_string_append_c (string, ',');
166 			str = gda_sql_field_serialize ((GdaSqlField*) list->data);
167 			g_string_append (string, str);
168 			g_free (str);
169 		}
170 		g_string_append_c (string, ']');
171 	}
172 	else
173 		g_string_append (string, "null");
174 
175 	/* values */
176 	if (insert->values_list) {
177 		g_string_append (string, ",\"values\":[");
178 		for (list = insert->values_list; list; list = list->next) {
179 			if (list != insert->values_list)
180 				g_string_append_c (string, ',');
181 			if (list->data) {
182 				GSList *vlist;
183 				g_string_append_c (string, '[');
184 				for (vlist = (GSList *) list->data; vlist; vlist = vlist->next) {
185 					if (vlist != (GSList *) list->data)
186 						g_string_append_c (string, ',');
187 					str = gda_sql_expr_serialize ((GdaSqlExpr*) vlist->data);
188 					g_string_append (string, str);
189 					g_free (str);
190 				}
191 				g_string_append_c (string, ']');
192 			}
193 			else
194 				g_string_append (string, "null");
195 		}
196 		g_string_append_c (string, ']');
197 	}
198 
199 	/* select statement */
200 	if (insert->select) {
201 		g_string_append (string, ",\"select\":{");
202 		if (GDA_SQL_ANY_PART (insert->select)->type == GDA_SQL_ANY_STMT_SELECT)
203 			str = _gda_sql_statement_select_serialize (insert->select);
204 		else if (GDA_SQL_ANY_PART (insert->select)->type == GDA_SQL_ANY_STMT_COMPOUND)
205 			str = _gda_sql_statement_compound_serialize (insert->select);
206 		else
207 			g_assert_not_reached ();
208 
209 		g_string_append (string, str);
210 		g_free (str);
211 		g_string_append_c (string, '}');
212 	}
213 
214 	/* conflict clause */
215 	if (insert->on_conflict) {
216 		g_string_append (string, ",\"on_conflict\":");
217 		str = _json_quote_string (insert->on_conflict);
218 		g_string_append (string, str);
219 		g_free (str);
220 	}
221 	g_string_append_c (string, '}');
222 	str = string->str;
223 	g_string_free (string, FALSE);
224 	return str;
225 }
226 
227 /**
228  * gda_sql_statement_insert_take_table_name
229  * @stmt: a #GdaSqlStatement pointer
230  * @value: name of the table to insert into, as a G_TYPE_STRING #GValue
231  *
232  * Sets the name of the table to insert into in @stmt. @value's ownership is transferred to
233  * @stmt (which means @stmt is then responsible for freeing it when no longer needed).
234  */
235 void
gda_sql_statement_insert_take_table_name(GdaSqlStatement * stmt,GValue * value)236 gda_sql_statement_insert_take_table_name (GdaSqlStatement *stmt, GValue *value)
237 {
238 	GdaSqlStatementInsert *insert = (GdaSqlStatementInsert *) stmt->contents;
239 	if (value) {
240 		insert->table = gda_sql_table_new (GDA_SQL_ANY_PART (insert));
241 		gda_sql_table_take_name (insert->table, value);
242 	}
243 }
244 
245 /**
246  * gda_sql_statement_insert_take_on_conflict
247  * @stmt: a #GdaSqlStatement pointer
248  * @value: name of the resolution conflict algorithm, as a G_TYPE_STRING #GValue
249  *
250  * Sets the name of the resolution conflict algorithm used by @stmt. @value's ownership is transferred to
251  * @stmt (which means @stmt is then responsible for freeing it when no longer needed).
252  */
253 void
gda_sql_statement_insert_take_on_conflict(GdaSqlStatement * stmt,GValue * value)254 gda_sql_statement_insert_take_on_conflict (GdaSqlStatement *stmt, GValue *value)
255 {
256 	GdaSqlStatementInsert *insert = (GdaSqlStatementInsert *) stmt->contents;
257 	if (value) {
258 		insert->on_conflict = g_value_dup_string (value);
259 		g_value_reset (value);
260 		g_free (value);
261 	}
262 }
263 
264 /**
265  * gda_sql_statement_insert_take_fields_list
266  * @stmt: a #GdaSqlStatement pointer
267  * @list: a list of #GdaSqlField pointers
268  *
269  * Sets the list of fields for which values will be specified in @stmt. @list's
270  * ownership is transferred to
271  * @stmt (which means @stmt is then responsible for freeing it when no longer needed).
272  */
273 void
gda_sql_statement_insert_take_fields_list(GdaSqlStatement * stmt,GSList * list)274 gda_sql_statement_insert_take_fields_list (GdaSqlStatement *stmt, GSList *list)
275 {
276 	GSList *l;
277 	GdaSqlStatementInsert *insert = (GdaSqlStatementInsert *) stmt->contents;
278 	insert->fields_list = list;
279 
280 	for (l = list; l; l = l->next)
281 		gda_sql_any_part_set_parent (l->data, insert);
282 }
283 
284 /**
285  * gda_sql_statement_insert_take_1_values_list
286  * @stmt: a #GdaSqlStatement pointer
287  * @list: a list of #GdaSqlExpr pointers
288  *
289  * Sets a list of values to be inserted by @stmt. @list's
290  * ownership is transferred to
291  * @stmt (which means @stmt is then responsible for freeing it when no longer needed).
292  */
293 void
gda_sql_statement_insert_take_1_values_list(GdaSqlStatement * stmt,GSList * list)294 gda_sql_statement_insert_take_1_values_list (GdaSqlStatement *stmt, GSList *list)
295 {
296 	GSList *l;
297 	GdaSqlStatementInsert *insert = (GdaSqlStatementInsert *) stmt->contents;
298 
299 	for (l = list; l; l = l->next)
300 		gda_sql_any_part_set_parent (l->data, insert);
301 	insert->values_list = g_slist_prepend (insert->values_list, list);
302 }
303 
304 /**
305  * gda_sql_statement_insert_take_1_values_list
306  * @stmt: a #GdaSqlStatement pointer
307  * @list: a list of #GSList of #GdaSqlExpr pointers
308  *
309  * Sets a list of list of values to be inserted by @stmt. @list's
310  * ownership is transferred to
311  * @stmt (which means @stmt is then responsible for freeing it when no longer needed).
312  */
313 void
gda_sql_statement_insert_take_extra_values_list(GdaSqlStatement * stmt,GSList * list)314 gda_sql_statement_insert_take_extra_values_list (GdaSqlStatement *stmt, GSList *list)
315 {
316 	GSList *l1, *l2;
317 	GdaSqlStatementInsert *insert = (GdaSqlStatementInsert *) stmt->contents;
318 	for (l1 = list; l1; l1 = l1->next) {
319 		for (l2 = (GSList *) l1->data; l2; l2 = l2->next)
320 			gda_sql_any_part_set_parent (l2->data, insert);
321 	}
322 	insert->values_list = g_slist_concat (insert->values_list, list);
323 }
324 
325 
326 /**
327  * gda_sql_statement_insert_take_select
328  * @stmt: a #GdaSqlStatement pointer
329  * @select: a SELECT or COMPOUND #GdaSqlStatement pointer
330  *
331  * Specifies a SELECT statement, the values inserted will be the result set of @select. @select's
332  * ownership is transferred to
333  * @stmt (which means @stmt is then responsible for freeing it when no longer needed).
334  */
335 void
gda_sql_statement_insert_take_select(GdaSqlStatement * stmt,GdaSqlStatement * select)336 gda_sql_statement_insert_take_select (GdaSqlStatement *stmt, GdaSqlStatement *select)
337 {
338 	GdaSqlStatementInsert *insert = (GdaSqlStatementInsert *) stmt->contents;
339 	GdaSqlAnyPart *part;
340 	part = GDA_SQL_ANY_PART (select->contents);
341 	select->contents = NULL;
342 	gda_sql_statement_free (select);
343 	insert->select = _gda_sql_statement_compound_reduce (part);
344 	gda_sql_any_part_set_parent (insert->select, insert);
345 }
346 
347 static gboolean
gda_sql_statement_insert_check_structure(GdaSqlAnyPart * stmt,G_GNUC_UNUSED gpointer data,GError ** error)348 gda_sql_statement_insert_check_structure (GdaSqlAnyPart *stmt, G_GNUC_UNUSED gpointer data, GError **error)
349 {
350 	GdaSqlStatementInsert *insert = (GdaSqlStatementInsert *) stmt;
351 	guint nb_values;
352 	GSList *list;
353 	if (!stmt) return TRUE;
354 
355 	nb_values = g_slist_length (insert->fields_list); /* may be 0 */
356 	if (!insert->table) {
357 		g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
358 			      "%s", _("INSERT statement needs a table to insert into"));
359 		return FALSE;
360 	}
361 	if (insert->select) {
362 		if (insert->values_list) {
363 			g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
364 				      "%s", _("Can't specify values to insert and SELECT statement in INSERT statement"));
365 			return FALSE;
366 		}
367 		if (nb_values > 0) {
368 			guint len;
369 			if (GDA_SQL_ANY_PART (insert->select)->type == GDA_SQL_ANY_STMT_SELECT) {
370 				GdaSqlStatementSelect *select = (GdaSqlStatementSelect*) insert->select;
371 				len = g_slist_length (select->expr_list);
372 			}
373 			else if (GDA_SQL_ANY_PART (insert->select)->type == GDA_SQL_ANY_STMT_COMPOUND) {
374 				gint compound_len;
375 				GdaSqlStatementCompound *compound = (GdaSqlStatementCompound*) insert->select;
376 				compound_len = _gda_sql_statement_compound_get_n_cols (compound, error);
377 				len = compound_len;
378 				if (compound_len < 0)
379 					return FALSE;
380 			}
381 			else
382 				g_assert_not_reached ();
383 			if (len != nb_values) {
384 				g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
385 					      "%s", _("INSERT statement does not have the same number of target columns and expressions"));
386 				return FALSE;
387 			}
388 		}
389 	}
390 	else {
391 		/* using values list */
392 		if (!insert->values_list && (nb_values != 0)) {
393 			g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
394 				      "%s", _("Missing values to insert in INSERT statement"));
395 			return FALSE;
396 		}
397 
398 		for (list = insert->values_list; list; list = list->next) {
399 			if (nb_values == 0) {
400 				nb_values = g_slist_length ((GSList *) list->data);
401 				if (nb_values == 0) {
402 					g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
403 						      "%s", _("Missing values to insert in INSERT statement"));
404 					return FALSE;
405 				}
406 			}
407 			else
408 				if (g_slist_length ((GSList *) list->data) != nb_values) {
409 					if (insert->fields_list)
410 						g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
411 							      "%s", _("INSERT statement does not have the same number of target columns and expressions"));
412 					else
413 						g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
414 							      "%s", _("VALUES lists must all be the same length in INSERT statement"));
415 					return FALSE;
416 				}
417 		}
418 	}
419         return TRUE;
420 }
421