1 /*
2  * Copyright (C) 2010 - 2012 Vivien Malerba <malerba@gnome-db.org>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  */
18 #include <libgda/libgda.h>
19 #include <libgda/sql-parser/gda-sql-parser.h>
20 #include <libgda/gda-blob-op.h>
21 
22 GdaConnection *open_connection (void);
23 static gboolean do_store (GdaConnection *cnc, const gchar *filename, GError **error);
24 static gboolean do_fetch (GdaConnection *cnc, gint id, GError **error);
25 static gboolean do_list (GdaConnection *cnc, GError **error);
26 
27 int
main(int argc,char * argv[])28 main (int argc, char *argv[])
29 {
30         GdaConnection *cnc;
31 	const gchar *filename = NULL;
32 	gint id = 0;
33 	GError *error = NULL;
34 	gboolean result;
35 
36 	/* parse arguments */
37         gda_init ();
38 	cnc = open_connection ();
39 
40 	if (! g_ascii_strcasecmp (argv[1], "store")) {
41 		if (argc != 3)
42 			goto help;
43 		filename = argv[2];
44 		result = do_store (cnc, filename, &error);
45 	}
46 	else if (! g_ascii_strcasecmp (argv[1], "fetch")) {
47 		if (argc != 3)
48 			goto help;
49 		id = atoi (argv[2]);
50 		result = do_fetch (cnc, id, &error);
51 	}
52 	else if (! g_ascii_strcasecmp (argv[1], "list")) {
53 		if (argc != 2)
54 			goto help;
55 		result = do_list (cnc, &error);
56 	}
57 	else
58 		goto help;
59 
60 	if (!result) {
61 		g_print ("ERROR: %s\n", error && error->message ? error->message : "No detail");
62 		g_clear_error (&error);
63 	}
64 	else
65 		g_print ("Ok.\n");
66 
67 	if (gda_connection_get_transaction_status (cnc))
68 		g_print ("Still in a transaction, all modifications will be lost when connection is closed\n");
69         gda_connection_close (cnc);
70 
71         return result ? 0 : 1;
72 
73  help:
74 	gda_connection_close (cnc);
75 	g_print ("%s [store <filename> | fetch <ID> | list]\n", argv[0]);
76 	return 0;
77 }
78 
79 /*
80  * Open a connection to the example.db file
81  */
82 GdaConnection *
open_connection(void)83 open_connection (void)
84 {
85         GdaConnection *cnc;
86         GError *error = NULL;
87         cnc = gda_connection_open_from_string ("SQLite", "DB_DIR=.;DB_NAME=testblob", NULL,
88 					       GDA_CONNECTION_OPTIONS_NONE,
89 					       &error);
90         if (!cnc) {
91                 g_print ("Could not open connection to SQLite database in testblob.db file: %s\n",
92                          error && error->message ? error->message : "No detail");
93                 exit (1);
94         }
95         return cnc;
96 }
97 
98 static gboolean
do_store(GdaConnection * cnc,const gchar * filename,GError ** error)99 do_store (GdaConnection *cnc, const gchar *filename, GError **error)
100 {
101 	if (! g_file_test (filename, G_FILE_TEST_EXISTS) ||
102 	    g_file_test (filename, G_FILE_TEST_IS_DIR)) {
103 		g_set_error (error, 0, 0,
104 			     "%s", "File does not exist or is a directory");
105 		return FALSE;
106 	}
107 
108 	GdaSqlParser *parser;
109 	GdaStatement *stmt;
110 	GdaSet *params, *newrow;
111 	GdaHolder *holder;
112 	GValue *value;
113 	gint res;
114 
115 	parser = gda_sql_parser_new ();
116 	stmt = gda_sql_parser_parse_string (parser,
117 					    "INSERT INTO blobstable (data) VALUES (##blob::blob)",
118 					    NULL, error);
119 	g_object_unref (parser);
120 	if (!stmt)
121 		return FALSE;
122 
123 	if (! gda_statement_get_parameters (stmt, &params, error)) {
124 		g_object_unref (stmt);
125 		return FALSE;
126 	}
127 
128 	holder = gda_set_get_holder (params, "blob");
129 	value = gda_value_new_blob_from_file (filename);
130 	g_assert (gda_holder_take_value (holder, value, NULL));
131 
132 	g_print ("Before writing BLOB: %s\n", gda_connection_get_transaction_status (cnc) ?
133 		 "Transaction started" : "No transaction started");
134 
135 	g_print ("STORING file '%s' to database BLOB\n", filename);
136 	res = gda_connection_statement_execute_non_select (cnc, stmt, params, &newrow, error);
137 	g_object_unref (params);
138 	g_object_unref (stmt);
139 
140 	g_print ("After writing BLOB: %s\n", gda_connection_get_transaction_status (cnc) ?
141 		 "Transaction started" : "No transaction started");
142 
143 	if (newrow) {
144 		GSList *list;
145 		g_print ("Inserted row is (for each numbered column in the table):\n");
146 		for (list = newrow->holders; list; list = list->next) {
147 			const GValue *value;
148 			gchar *tmp;
149 			value = gda_holder_get_value (GDA_HOLDER (list->data));
150 			tmp = gda_value_stringify (value);
151 			g_print ("  [%s] = [%s]\n", gda_holder_get_id (GDA_HOLDER (list->data)), tmp);
152 			g_free (tmp);
153 		}
154 		g_object_unref (newrow);
155 	}
156 	else
157 		g_print ("Provider did not return the inserted row\n");
158 
159 	gda_connection_rollback_transaction (cnc, NULL, NULL);
160 	g_print ("After rolling back blob READ transaction: %s\n", gda_connection_get_transaction_status (cnc) ?
161 		 "Transaction started" : "No transaction started");
162 
163 	return (res == -1) ? FALSE : TRUE;
164 }
165 
166 static gboolean
do_fetch(GdaConnection * cnc,gint id,GError ** error)167 do_fetch (GdaConnection *cnc, gint id, GError **error)
168 {
169 	GdaSqlParser *parser;
170 	GdaStatement *stmt;
171 	GdaSet *params;
172 	GdaDataModel *model;
173 	const GValue *value;
174 	GdaBlob *blob;
175 	gboolean result = TRUE;
176 
177 	g_print ("Before reading BLOB: %s\n", gda_connection_get_transaction_status (cnc) ?
178 		 "Transaction started" : "No transaction started");
179 
180 	gchar *filename;
181 	filename = g_strdup_printf ("fetched_%d", id);
182 	g_print ("FETCHING BLOB with ID %d to file '%s'\n", id, filename);
183 
184 	parser = gda_sql_parser_new ();
185 	stmt = gda_sql_parser_parse_string (parser,
186 					    "SELECT data FROM blobstable WHERE id=##id::int",
187 					    NULL, error);
188 	g_object_unref (parser);
189 	if (!stmt)
190 		return FALSE;
191 
192 	if (! gda_statement_get_parameters (stmt, &params, error)) {
193 		g_object_unref (stmt);
194 		return FALSE;
195 	}
196 	g_assert (gda_set_set_holder_value (params, NULL, "id", id));
197 	model = gda_connection_statement_execute_select (cnc, stmt, params, error);
198 	g_object_unref (params);
199 	g_object_unref (stmt);
200 	if (! model)
201 		return FALSE;
202 
203 	g_print ("After reading BLOB: %s\n", gda_connection_get_transaction_status (cnc) ?
204 		 "Transaction started" : "No transaction started");
205 
206 	value = gda_data_model_get_value_at (model, 0, 0, error);
207 	if (!value) {
208 		g_object_unref (model);
209 		return FALSE;
210 	}
211 	g_assert (G_VALUE_TYPE (value) == GDA_TYPE_BLOB);
212 
213 	blob = (GdaBlob*) gda_value_get_blob (value);
214 	if (blob->op) {
215 		GValue *dest_value;
216 		GdaBlob *dest_blob;
217 
218 		dest_value = gda_value_new_blob_from_file (filename);
219 		dest_blob = (GdaBlob*) gda_value_get_blob (dest_value);
220 		result = gda_blob_op_write_all (dest_blob->op, (GdaBlob*) blob);
221 		gda_value_free (dest_value);
222 	}
223 	else
224 		result = g_file_set_contents (filename, (gchar *) ((GdaBinary*)blob)->data,
225 					     ((GdaBinary*)blob)->binary_length, error);
226 	g_free (filename);
227 	g_object_unref (model);
228 
229 	gda_connection_rollback_transaction (cnc, NULL, NULL);
230 	g_print ("After rolling back blob READ transaction: %s\n", gda_connection_get_transaction_status (cnc) ?
231 		 "Transaction started" : "No transaction started");
232 
233 	return result;
234 }
235 
236 static gboolean
do_list(GdaConnection * cnc,GError ** error)237 do_list (GdaConnection *cnc, GError **error)
238 {
239 	GdaDataModel *model;
240 
241 	model = gda_connection_execute_select_command (cnc, "SELECT * FROM blobstable", error);
242 	if (model) {
243 		gda_data_model_dump (model, stdout);
244 		return TRUE;
245 	}
246 	else
247 		return FALSE;
248 }
249