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-update.h>
26 #include <libgda/sql-parser/gda-statement-struct-util.h>
27 #include <libgda/sql-parser/gda-statement-struct-pspec.h>
28 #include <string.h>
29 #include <glib/gi18n-lib.h>
30 
31 static gpointer  gda_sql_statement_update_new (void);
32 static void      gda_sql_statement_update_free (gpointer stmt);
33 static gpointer  gda_sql_statement_update_copy (gpointer src);
34 static gchar    *gda_sql_statement_update_serialize (gpointer stmt);
35 static gboolean  gda_sql_statement_update_check_structure (GdaSqlAnyPart *stmt, gpointer data, GError **error);
36 
37 GdaSqlStatementContentsInfo update_infos = {
38 	GDA_SQL_STATEMENT_UPDATE,
39 	"UPDATE",
40 	gda_sql_statement_update_new,
41 	gda_sql_statement_update_free,
42 	gda_sql_statement_update_copy,
43 	gda_sql_statement_update_serialize,
44 
45 	gda_sql_statement_update_check_structure,
46 	NULL,
47 	NULL,
48 	NULL,
49 	NULL,
50 	NULL
51 };
52 
53 GdaSqlStatementContentsInfo *
_gda_sql_statement_update_get_infos(void)54 _gda_sql_statement_update_get_infos (void)
55 {
56 	return &update_infos;
57 }
58 
59 static gpointer
gda_sql_statement_update_new(void)60 gda_sql_statement_update_new (void)
61 {
62 	GdaSqlStatementUpdate *stmt;
63 	stmt = g_new0 (GdaSqlStatementUpdate, 1);
64 	GDA_SQL_ANY_PART (stmt)->type = GDA_SQL_ANY_STMT_UPDATE;
65 	return (gpointer) stmt;
66 }
67 
68 static void
gda_sql_statement_update_free(gpointer stmt)69 gda_sql_statement_update_free (gpointer stmt)
70 {
71 	GdaSqlStatementUpdate *update = (GdaSqlStatementUpdate *) stmt;
72 	GSList *list;
73 
74 	if (update->table)
75 		gda_sql_table_free (update->table);
76 	for (list = update->fields_list; list; list = list->next) {
77 		if (list->data)
78 			gda_sql_field_free ((GdaSqlField *) list->data);
79 	}
80 	if (update->fields_list)
81 		g_slist_free (update->fields_list);
82 
83 	for (list = update->expr_list; list; list = list->next) {
84 		if (list->data)
85 			gda_sql_expr_free ((GdaSqlExpr *) list->data);
86 	}
87 	if (update->expr_list)
88 		g_slist_free (update->expr_list);
89 
90 	if (update->cond)
91 		gda_sql_expr_free (update->cond);
92 	g_free (update);
93 }
94 
95 static gpointer
gda_sql_statement_update_copy(gpointer src)96 gda_sql_statement_update_copy (gpointer src)
97 {
98 	GdaSqlStatementUpdate *dest;
99 	GdaSqlStatementUpdate *update = (GdaSqlStatementUpdate *) src;
100 	GSList *list;
101 
102 	dest = gda_sql_statement_update_new ();
103 	if (update->on_conflict)
104                 dest->on_conflict = g_strdup (update->on_conflict);
105 
106 	dest->table = gda_sql_table_copy (update->table);
107 	gda_sql_any_part_set_parent (dest->table, dest);
108 
109 	for (list = update->fields_list; list; list = list->next) {
110 		dest->fields_list = g_slist_prepend (dest->fields_list,
111 						     gda_sql_field_copy ((GdaSqlField *) list->data));
112 		gda_sql_any_part_set_parent (dest->fields_list->data, dest);
113 	}
114 	dest->fields_list = g_slist_reverse (dest->fields_list);
115 
116 	for (list = update->expr_list; list; list = list->next) {
117 		dest->expr_list = g_slist_prepend (dest->expr_list,
118 						   gda_sql_expr_copy ((GdaSqlExpr *) list->data));
119 		gda_sql_any_part_set_parent (dest->expr_list->data, dest);
120 	}
121 	dest->expr_list = g_slist_reverse (dest->expr_list);
122 
123 	dest->cond = gda_sql_expr_copy (update->cond);
124 	gda_sql_any_part_set_parent (dest->cond, dest);
125 
126 	return dest;
127 }
128 
129 static gchar *
gda_sql_statement_update_serialize(gpointer stmt)130 gda_sql_statement_update_serialize (gpointer stmt)
131 {
132 	GString *string;
133 	gchar *str;
134 	GSList *list;
135 	GdaSqlStatementUpdate *update = (GdaSqlStatementUpdate *) stmt;
136 
137 	g_return_val_if_fail (stmt, NULL);
138 
139 	string = g_string_new ("\"contents\":{");
140 
141 	/* table name */
142 	g_string_append (string, "\"table\":");
143 	str = gda_sql_table_serialize (update->table);
144 	g_string_append (string, str);
145 	g_free (str);
146 
147 	/* fields */
148 	g_string_append (string, ",\"fields\":");
149 	if (update->fields_list) {
150 		g_string_append_c (string, '[');
151 		for (list = update->fields_list; list; list = list->next) {
152 			if (list != update->fields_list)
153 				g_string_append_c (string, ',');
154 			str = gda_sql_field_serialize ((GdaSqlField *) list->data);
155 			g_string_append (string, str);
156 			g_free (str);
157 		}
158 		g_string_append_c (string, ']');
159 	}
160 	else
161 		g_string_append (string, "null");
162 
163 	/* expressions */
164 	g_string_append (string, ",\"expressions\":");
165 	if (update->expr_list) {
166 		g_string_append_c (string, '[');
167 		for (list = update->expr_list; list; list = list->next) {
168 			if (list != update->expr_list)
169 				g_string_append_c (string, ',');
170 			str = gda_sql_expr_serialize ((GdaSqlExpr *) list->data);
171 			g_string_append (string, str);
172 			g_free (str);
173 		}
174 		g_string_append_c (string, ']');
175 	}
176 	else
177 		g_string_append (string, "null");
178 
179 	/* condition */
180 	if (update->cond) {
181 		g_string_append (string, ",\"condition\":");
182 		str = gda_sql_expr_serialize (update->cond);
183 		g_string_append (string, str);
184 		g_free (str);
185 	}
186 
187 	/* conflict clause */
188         if (update->on_conflict) {
189                 g_string_append (string, ",\"on_conflict\":");
190                 str = _json_quote_string (update->on_conflict);
191                 g_string_append (string, str);
192                 g_free (str);
193         }
194 	g_string_append_c (string, '}');
195 	str = string->str;
196 	g_string_free (string, FALSE);
197 	return str;
198 }
199 
200 /**
201  * gda_sql_statement_update_take_table_name
202  * @stmt: a #GdaSqlStatement pointer
203  * @value: a table name, as a G_TYPE_STRING #GValue
204  *
205  * Sets the name of the table to delete from in @stmt.
206  *
207  * @value's ownership is transferred to
208  * @stmt (which means @stmt is then responsible for freeing it when no longer needed).
209  */
210 void
gda_sql_statement_update_take_table_name(GdaSqlStatement * stmt,GValue * value)211 gda_sql_statement_update_take_table_name (GdaSqlStatement *stmt, GValue *value)
212 {
213 	GdaSqlStatementUpdate *update = (GdaSqlStatementUpdate *) stmt->contents;
214 	if (value) {
215 		update->table = gda_sql_table_new (GDA_SQL_ANY_PART (update));
216 		gda_sql_table_take_name (update->table, value);
217 	}
218 }
219 
220 /**
221  * gda_sql_statement_update_take_on_conflict
222  * @stmt: a #GdaSqlStatement pointer
223  * @value: name of the resolution conflict algorithm, as a G_TYPE_STRING #GValue
224  *
225  * Sets the name of the resolution conflict algorithm used by @stmt. @value's ownership is transferred to
226  * @stmt (which means @stmt is then responsible for freeing it when no longer needed).
227  */
228 void
gda_sql_statement_update_take_on_conflict(GdaSqlStatement * stmt,GValue * value)229 gda_sql_statement_update_take_on_conflict (GdaSqlStatement *stmt, GValue *value)
230 {
231 	GdaSqlStatementUpdate *update = (GdaSqlStatementUpdate *) stmt->contents;
232         if (value) {
233                 update->on_conflict = g_value_dup_string (value);
234                 g_value_reset (value);
235                 g_free (value);
236         }
237 }
238 
239 /**
240  * gda_sql_statement_update_take_condition
241  * @stmt: a #GdaSqlStatement pointer
242  * @cond: a #GdaSqlExpr pointer
243  *
244  * Sets the WHERE clause of @stmt
245  *
246  * @expr's ownership is transferred to
247  * @stmt (which means @stmt is then responsible for freeing it when no longer needed).
248  */
249 void
gda_sql_statement_update_take_condition(GdaSqlStatement * stmt,GdaSqlExpr * cond)250 gda_sql_statement_update_take_condition (GdaSqlStatement *stmt, GdaSqlExpr *cond)
251 {
252 	GdaSqlStatementUpdate *update = (GdaSqlStatementUpdate *) stmt->contents;
253 	update->cond = cond;
254 	gda_sql_any_part_set_parent (cond, update);
255 }
256 
257 
258 /**
259  * gda_sql_statement_update_take_set_value
260  * @stmt: a #GdaSqlStatement pointer
261  * @fname: a field name, as a G_TYPE_STRING #GValue
262  * @expr: a #GdaSqlExpr pointer
263  *
264  * Specifies that the field named @fname will be updated with the expression @expr.
265  *
266  * @fname and @expr's responsibility are transferred to
267  * @stmt (which means @stmt is then responsible for freeing them when no longer needed).
268  */
269 void
gda_sql_statement_update_take_set_value(GdaSqlStatement * stmt,GValue * fname,GdaSqlExpr * expr)270 gda_sql_statement_update_take_set_value (GdaSqlStatement *stmt, GValue *fname, GdaSqlExpr *expr)
271 {
272 	GdaSqlStatementUpdate *update = (GdaSqlStatementUpdate *) stmt->contents;
273 	GdaSqlField *sf;
274 
275 	sf = gda_sql_field_new (GDA_SQL_ANY_PART (update));
276 	gda_sql_field_take_name (sf, fname);
277 	update->fields_list = g_slist_append (update->fields_list, sf);
278 
279 	update->expr_list = g_slist_append (update->expr_list, expr);
280 	gda_sql_any_part_set_parent (expr, update);
281 }
282 
283 static gboolean
gda_sql_statement_update_check_structure(GdaSqlAnyPart * stmt,G_GNUC_UNUSED gpointer data,GError ** error)284 gda_sql_statement_update_check_structure (GdaSqlAnyPart *stmt, G_GNUC_UNUSED gpointer data, GError **error)
285 {
286 	GdaSqlStatementUpdate *update = (GdaSqlStatementUpdate *) stmt;
287 
288 	if (!update->table) {
289 		g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
290 			      "%s", _("UPDATE statement needs a table to update data"));
291 		return FALSE;
292 	}
293 
294 	if (g_slist_length (update->fields_list) != g_slist_length (update->expr_list)) {
295 		g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
296 			      "%s", _("UPDATE statement does not have the same number of target columns and expressions"));
297 		return FALSE;
298 	}
299 
300 	if (!update->fields_list) {
301 		g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
302 			      "%s", _("UPDATE statement does not have any target columns to update"));
303 		return FALSE;
304 	}
305 
306         return TRUE;
307 }
308