1 /* Widgets/DDL queries
2 *
3 * A DDL query is a query defining or modifying a database structure and properties.
4 * In Libgda, each type of DDL query corresponds to an "operation".
5 * Examples of "operation"s include creating a database, creating a table,
6 * adding a field to a table.
7 *
8 * Because the SQL corresponding to DDL queries varies widely between the
9 * DBMS, the information required to perform an operation is provided by
10 * each DBMS adapter (server provider), and specified as a set of named
11 * parameters.
12 *
13 * For each type of operation and for each type of provider, a GdaServerOperation
14 * object can be requested; this objects holds all the named parameters required
15 * or optional to perform the operation. Once values have been set to the
16 * named parameters, that object is passed back to the provider which can render
17 * it as SQL or perform the requested operation.
18 *
19 * The GdauiServerOperation widget can be used to display
20 * and assign value to the named parameters of a GdaServerOperation object.
21 */
22
23 #include <libgda-ui/libgda-ui.h>
24 #include <string.h>
25
26 static GtkWidget *window = NULL;
27
28 typedef struct {
29 GdaServerOperation *op;
30 GtkWidget *op_container;
31 GtkWidget *op_form;
32 GdauiProviderSelector *prov_sel;
33 GtkWidget *op_combo;
34 GdaServerProvider *prov;
35
36 GtkWidget *top_window;
37 GtkWidget *sql_button;
38 GtkWidget *show_button;
39 } DemoData;
40
41 static void tested_provider_changed_cb (GdauiProviderSelector *prov_sel, DemoData *data);
42 static void tested_operation_changed_cb (GdauiCombo *combo, DemoData *data);
43 static void update_possible_operations (DemoData *data);
44
45 static void show_named_parameters (GtkButton *button, DemoData *data);
46 static void show_sql (GtkButton *button, DemoData *data);
47
48 static GdaServerProvider *get_provider_obj (DemoData *data);
49
50 GtkWidget *
do_ddl_queries(GtkWidget * do_widget)51 do_ddl_queries (GtkWidget *do_widget)
52 {
53 if (!window) {
54 GtkWidget *grid;
55 GtkWidget *label;
56 GtkWidget *wid;
57 DemoData *data;
58 GtkWidget *bbox;
59 GtkWidget *sw, *vp;
60
61 data = g_new0 (DemoData, 1);
62
63 window = gtk_dialog_new_with_buttons ("DDL queries",
64 GTK_WINDOW (do_widget),
65 0,
66 GTK_STOCK_CLOSE,
67 GTK_RESPONSE_NONE,
68 NULL);
69 data->top_window = window;
70
71 g_signal_connect (window, "response",
72 G_CALLBACK (gtk_widget_destroy), NULL);
73 g_signal_connect (window, "destroy",
74 G_CALLBACK (gtk_widget_destroyed), &window);
75
76 grid = gtk_grid_new ();
77 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))),
78 grid, TRUE, TRUE, 0);
79 gtk_container_set_border_width (GTK_CONTAINER (grid), 5);
80
81 label = gtk_label_new ("<b>Tested provider and operation:</b>");
82 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
83 gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
84 gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 2, 1);
85
86 /* provider selection */
87 label = gtk_label_new ("Tested provider:");
88 gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
89 gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 1, 1);
90
91 wid = gdaui_provider_selector_new ();
92 gdaui_provider_selector_set_provider (GDAUI_PROVIDER_SELECTOR (wid),
93 "SQLite");
94 gtk_grid_attach (GTK_GRID (grid), wid, 1, 1, 1, 1);
95 data->prov_sel = GDAUI_PROVIDER_SELECTOR (wid);
96 g_signal_connect (G_OBJECT (data->prov_sel), "changed",
97 G_CALLBACK (tested_provider_changed_cb), data);
98
99 /* operation selection */
100 label = gtk_label_new ("Tested operation:");
101 gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
102 gtk_grid_attach (GTK_GRID (grid), label, 0, 2, 1, 1);
103
104 wid = gdaui_combo_new ();
105 gtk_grid_attach (GTK_GRID (grid), wid, 1, 2, 1, 1);
106 g_signal_connect (G_OBJECT (wid), "changed",
107 G_CALLBACK (tested_operation_changed_cb), data);
108 data->op_combo = wid;
109
110 /* container for GdauiServerOperation */
111 label = gtk_label_new ("<b>GdauiServerOperation widget:</b>");
112 gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
113 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
114 gtk_grid_attach (GTK_GRID (grid), label, 0, 3, 2, 1);
115
116 sw = gtk_scrolled_window_new (FALSE, 0);
117 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
118 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
119 gtk_widget_set_size_request (sw, 600, 450);
120 gtk_grid_attach (GTK_GRID (grid), sw, 0, 4, 2, 1);
121 vp = gtk_viewport_new (NULL, NULL);
122 gtk_widget_set_name (vp, "gdaui-transparent-background");
123 gtk_viewport_set_shadow_type (GTK_VIEWPORT (vp), GTK_SHADOW_NONE);
124 gtk_container_add (GTK_CONTAINER (sw), vp);
125 data->op_container = vp;
126
127 /* bottom buttons */
128 bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
129 gtk_grid_attach (GTK_GRID (grid), bbox, 0, 5, 2, 1);
130
131 wid = gtk_button_new_with_label ("Show named parameters");
132 data->show_button = wid;
133 gtk_box_pack_start (GTK_BOX (bbox), wid, TRUE, TRUE, 0);
134 g_signal_connect (G_OBJECT (wid), "clicked",
135 G_CALLBACK (show_named_parameters), data);
136
137 wid = gtk_button_new_with_label ("Show SQL");
138 data->sql_button = wid;
139 gtk_box_pack_start (GTK_BOX (bbox), wid, TRUE, TRUE, 0);
140 g_signal_connect (G_OBJECT (wid), "clicked",
141 G_CALLBACK (show_sql), data);
142
143 tested_provider_changed_cb (data->prov_sel, data);
144 gtk_combo_box_set_active (GTK_COMBO_BOX (data->op_combo), 1);
145 }
146
147 gboolean visible;
148 g_object_get (G_OBJECT (window), "visible", &visible, NULL);
149 if (!visible)
150 gtk_widget_show_all (window);
151 else {
152 gtk_widget_destroy (window);
153 window = NULL;
154 }
155
156 return window;
157 }
158
159 static void
tested_provider_changed_cb(G_GNUC_UNUSED GdauiProviderSelector * prov_sel,DemoData * data)160 tested_provider_changed_cb (G_GNUC_UNUSED GdauiProviderSelector *prov_sel, DemoData *data)
161 {
162 if (data->prov) {
163 g_object_unref (data->prov);
164 data->prov = NULL;
165 }
166 update_possible_operations (data);
167 }
168
169 static void
update_possible_operations(DemoData * data)170 update_possible_operations (DemoData *data)
171 {
172 GdaServerOperationType type;
173 GdaDataModel *model;
174
175 model = gdaui_data_selector_get_model (GDAUI_DATA_SELECTOR (data->op_combo));
176 if (!model) {
177 gint columns[] = {1};
178 model = gda_data_model_array_new_with_g_types (2, G_TYPE_INT, G_TYPE_STRING);
179 gdaui_combo_set_model (GDAUI_COMBO (data->op_combo), model, 1, columns);
180 }
181 else
182 gda_data_model_array_clear (GDA_DATA_MODEL_ARRAY (model));
183
184 for (type = 0; type < GDA_SERVER_OPERATION_LAST; type ++)
185 if (gda_server_provider_supports_operation (get_provider_obj (data),
186 NULL, type, NULL)) {
187 gint row;
188
189 row = gda_data_model_append_row (model, NULL);
190 if (row < 0)
191 g_error ("Cant' append data to a GdaDataModelArray");
192 else {
193 GValue value;
194
195 memset (&value, 0, sizeof (GValue));
196 g_value_init (&value, G_TYPE_INT);
197 g_value_set_int (&value, type);
198 gda_data_model_set_value_at (model, 0, row, &value, NULL);
199
200 memset (&value, 0, sizeof (GValue));
201 g_value_init (&value, G_TYPE_STRING);
202 g_value_set_string (&value, gda_server_operation_op_type_to_string (type));
203 gda_data_model_set_value_at (model, 1, row, &value, NULL);
204 }
205 }
206 }
207
208 static GdaServerProvider *
get_provider_obj(DemoData * data)209 get_provider_obj (DemoData *data)
210 {
211 GdaServerProvider *prov = NULL;
212
213 if (data->prov)
214 prov = data->prov;
215 else {
216 /* create the GdaServerProvider object */
217 data->prov = gdaui_provider_selector_get_provider_obj (data->prov_sel);
218 prov = data->prov;
219 }
220
221 return prov;
222 }
223
224 static void
tested_operation_changed_cb(G_GNUC_UNUSED GdauiCombo * combo,DemoData * data)225 tested_operation_changed_cb (G_GNUC_UNUSED GdauiCombo *combo, DemoData *data)
226 {
227 GdaServerProvider *prov = NULL;
228 GdaServerOperationType type;
229 GError *error = NULL;
230 GdaDataModelIter *iter;
231 const GValue *cvalue = NULL;
232
233 if (data->op) {
234 g_object_unref (data->op);
235 data->op = NULL;
236 }
237 if (data->op_form)
238 gtk_widget_destroy (data->op_form);
239
240 gtk_widget_set_sensitive (data->show_button, FALSE);
241 gtk_widget_set_sensitive (data->sql_button, FALSE);
242
243 iter = gdaui_data_selector_get_data_set (GDAUI_DATA_SELECTOR (data->op_combo));
244 if (iter)
245 cvalue = gda_data_model_iter_get_value_at (iter, 0);
246 if (!cvalue || !gda_value_isa ((GValue *) cvalue, G_TYPE_INT)) {
247 GtkWidget *label;
248
249 label = gtk_label_new ("Select an operation to perform");
250 gtk_container_add (GTK_CONTAINER (data->op_container), label);
251 data->op_form = label;
252 gtk_widget_show (data->op_form);
253 return;
254 }
255 type = g_value_get_int ((GValue *) cvalue);
256
257 prov = get_provider_obj (data);
258 if (prov)
259 data->op = gda_server_provider_create_operation (prov, NULL, type, NULL, &error);
260
261 if (!data->op) {
262 GtkWidget *label;
263 gchar *str;
264
265 str = g_strdup_printf ("Can't create GdaServerOperation widget: %s",
266 error && error->message ? error->message : "No detail");
267 label = gtk_label_new (str);
268 g_free (str);
269 gtk_container_add (GTK_CONTAINER (data->op_container), label);
270 data->op_form = label;
271 }
272 else {
273 GtkWidget *wid;
274
275 wid = gdaui_server_operation_new (data->op);
276 gtk_container_add (GTK_CONTAINER (data->op_container), wid);
277 data->op_form = wid;
278 gtk_widget_set_sensitive (data->show_button, TRUE);
279 gtk_widget_set_sensitive (data->sql_button, TRUE);
280 }
281 gtk_widget_show (data->op_form);
282 }
283
284 static void
extract_named_parameters(GdaServerOperation * op,const gchar * root_path,GtkTextBuffer * tbuffer)285 extract_named_parameters (GdaServerOperation *op, const gchar *root_path, GtkTextBuffer *tbuffer)
286 {
287 GdaServerOperationNode *node;
288 GtkTextIter iter;
289 gchar *str;
290
291 node = gda_server_operation_get_node_info (op, root_path);
292 g_return_if_fail (node);
293
294 gtk_text_buffer_get_end_iter (tbuffer, &iter);
295
296 gtk_text_buffer_insert (tbuffer, &iter, " * ", -1);
297 if (node->status == GDA_SERVER_OPERATION_STATUS_REQUIRED)
298 gtk_text_buffer_insert_with_tags_by_name (tbuffer, &iter, root_path, -1, "req_pathname", NULL);
299 else
300 gtk_text_buffer_insert_with_tags_by_name (tbuffer, &iter, root_path, -1, "opt_pathname", NULL);
301 gtk_text_buffer_insert (tbuffer, &iter, " (", -1);
302
303 switch (node->type) {
304 case GDA_SERVER_OPERATION_NODE_PARAMLIST: {
305 GSList *params;
306
307 str = g_strdup_printf ("GdaSet @%p)\n", node->plist);
308 gtk_text_buffer_insert (tbuffer, &iter, str, -1);
309 g_free (str);
310
311 for (params = node->plist->holders; params; params = params->next) {
312 gchar *npath;
313 npath = g_strdup_printf ("%s/%s", root_path, gda_holder_get_id (GDA_HOLDER (params->data)));
314 extract_named_parameters (op, npath, tbuffer);
315 g_free (npath);
316 }
317
318 break;
319 }
320 case GDA_SERVER_OPERATION_NODE_DATA_MODEL: {
321 gint i, ncols;
322
323 str = g_strdup_printf ("GdaDataModel @%p)\n", node->model);
324 gtk_text_buffer_insert (tbuffer, &iter, str, -1);
325 g_free (str);
326
327 ncols = gda_data_model_get_n_columns (node->model);
328 for (i = 0; i < ncols; i++) {
329 GdaColumn *col = gda_data_model_describe_column (node->model, i);
330 gchar *npath, *str;
331
332 g_object_get (G_OBJECT (col), "id", &str, NULL);
333 npath = g_strdup_printf ("%s/@%s", root_path, str);
334 g_free (str);
335 extract_named_parameters (op, npath, tbuffer);
336 g_free (npath);
337 }
338 break;
339 }
340 case GDA_SERVER_OPERATION_NODE_PARAM: {
341 gchar *str;
342 const GValue *value;
343
344 gtk_text_buffer_insert (tbuffer, &iter, "GdaHolder) = ", -1);
345
346 value = gda_holder_get_value (node->param);
347 str = gda_value_stringify (value);
348 gtk_text_buffer_insert (tbuffer, &iter, str, -1);
349 gtk_text_buffer_insert (tbuffer, &iter, "\n", -1);
350 g_free (str);
351 break;
352 }
353 case GDA_SERVER_OPERATION_NODE_SEQUENCE: {
354 gtk_text_buffer_insert (tbuffer, &iter, "Sequence)\n", -1);
355 guint i, size = gda_server_operation_get_sequence_size (op, root_path);
356 for (i = 0; i < size; i++) {
357 gchar **names;
358 names = gda_server_operation_get_sequence_item_names (op, root_path);
359 guint n;
360 for (n = 0; names [n]; n++) {
361 gchar *npath;
362 npath = g_strdup_printf ("%s/%u%s", root_path, i, names [n]);
363 extract_named_parameters (op, npath, tbuffer);
364 g_free (npath);
365 }
366 g_strfreev (names);
367 }
368 break;
369 }
370
371 case GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM:
372 gtk_text_buffer_insert (tbuffer, &iter, "Sequence item)\n", -1);
373 break;
374
375 case GDA_SERVER_OPERATION_NODE_DATA_MODEL_COLUMN: {
376 gint j, nrows;
377
378 gtk_text_buffer_insert (tbuffer, &iter, "Model column)\n", -1);
379
380 nrows = gda_data_model_get_n_rows (node->model);
381 for (j = 0; j < nrows; j++) {
382 gchar *npath, *str;
383 const GValue *value;
384
385 npath = g_strdup_printf ("%s/%d", root_path, j);
386 value = gda_data_model_get_value_at (node->model, gda_column_get_position (node->column), j, NULL);
387 if (value)
388 str = gda_value_stringify (value);
389 else
390 str = g_strdup ("Error: could not read data model's value");
391 gtk_text_buffer_insert (tbuffer, &iter, " * ", -1);
392 gtk_text_buffer_insert_with_tags_by_name (tbuffer, &iter, npath, -1, "opt_pathname", NULL);
393 g_free (npath);
394 gtk_text_buffer_insert (tbuffer, &iter, " (GValue) = ", -1);
395 gtk_text_buffer_insert (tbuffer, &iter, str, -1);
396 gtk_text_buffer_insert (tbuffer, &iter, "\n", -1);
397 g_free (str);
398 }
399
400 break;
401 }
402 default:
403 gtk_text_buffer_insert (tbuffer, &iter, "???", -1);
404 break;
405 }
406 }
407
408 static void
show_named_parameters(G_GNUC_UNUSED GtkButton * button,DemoData * data)409 show_named_parameters (G_GNUC_UNUSED GtkButton *button, DemoData *data)
410 {
411 GtkWidget *dlg, *label;
412 gchar **root_nodes;
413 gint i;
414 GtkWidget *view;
415 GtkWidget *sw;
416 GtkTextBuffer *buffer;
417 GtkTextIter iter;
418
419 if (!data->op || !data->op_form || ! GDAUI_IS_SERVER_OPERATION (data->op_form))
420 return;
421
422 /* dialog box */
423 dlg = gtk_dialog_new_with_buttons ("Named parameters",
424 GTK_WINDOW (data->top_window),
425 GTK_DIALOG_MODAL,
426 GTK_STOCK_CLOSE, GTK_RESPONSE_REJECT, NULL);
427
428 label = gtk_label_new ("<b>Named parameters:</b>\n");
429 gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
430 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
431 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
432 label, FALSE, FALSE, 0);
433 gtk_widget_show (label);
434
435 /* text area */
436 view = gtk_text_view_new ();
437 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
438 gtk_text_buffer_get_start_iter (buffer, &iter);
439 gtk_text_buffer_create_tag (buffer, "opt_pathname",
440 "weight", PANGO_WEIGHT_BOLD,
441 "foreground", "grey", NULL);
442 gtk_text_buffer_create_tag (buffer, "req_pathname",
443 "weight", PANGO_WEIGHT_BOLD,
444 "foreground", "blue", NULL);
445
446 xmlNodePtr xml;
447 xml = gda_server_operation_save_data_to_xml (data->op, NULL);
448 if (xml) {
449 g_print ("XML rendering of the GdaServerOperation is:\n");
450 xmlBufferPtr buffer;
451 buffer = xmlBufferCreate ();
452 xmlNodeDump (buffer, NULL, xml, 0, 1);
453 xmlFreeNode (xml);
454 xmlBufferDump (stdout, buffer);
455 xmlBufferFree (buffer);
456 g_print ("\n");
457 }
458 else {
459 g_print ("XML rendering ERROR\n");
460 }
461
462 root_nodes = gda_server_operation_get_root_nodes (data->op);
463 for (i = 0; root_nodes && root_nodes[i]; i++)
464 extract_named_parameters (data->op, root_nodes[i], buffer);
465 g_strfreev (root_nodes);
466
467 sw = gtk_scrolled_window_new (NULL, NULL);
468 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
469 GTK_POLICY_AUTOMATIC,
470 GTK_POLICY_AUTOMATIC);
471 gtk_container_add (GTK_CONTAINER (sw), view);
472 gtk_widget_show_all (sw);
473
474 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
475 sw, TRUE, TRUE, 0);
476 gtk_widget_set_size_request (dlg, 530, 350);
477
478 gtk_dialog_run (GTK_DIALOG (dlg));
479 gtk_widget_destroy (dlg);
480 }
481
482 static void
show_sql(G_GNUC_UNUSED GtkButton * button,DemoData * data)483 show_sql (G_GNUC_UNUSED GtkButton *button, DemoData *data)
484 {
485 GdaServerProvider *prov;
486
487 if (!data->op)
488 return;
489
490 prov = get_provider_obj (data);
491 if (prov) {
492 gchar *sql, *msg;
493 GtkMessageType msg_type = GTK_MESSAGE_INFO;
494 GtkWidget *dlg;
495 GError *error = NULL;
496
497 sql = gda_server_provider_render_operation (prov, NULL, data->op, &error);
498 if (!sql) {
499 msg_type = GTK_MESSAGE_ERROR;
500 msg = g_strdup_printf ("<b>Can't render operation as SQL:</b>\n%s\n",
501 error && error->message ? error->message :
502 "No detail (This operation may not be accessible using SQL)");
503 if (error)
504 g_error_free (error);
505 }
506 else
507 msg = g_strdup_printf ("<b>SQL:</b>\n%s", sql);
508
509 dlg = gtk_message_dialog_new (GTK_WINDOW (data->top_window),
510 GTK_DIALOG_MODAL, msg_type, GTK_BUTTONS_CLOSE, NULL);
511 gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dlg), msg);
512 g_free (sql);
513 g_free (msg);
514
515 gtk_dialog_run (GTK_DIALOG (dlg));
516 gtk_widget_destroy (dlg);
517 }
518 else
519 g_warning ("Could not get provider object");
520 }
521