1 /*
2  * Copyright (C) 2013 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 
19 #include <libgda/libgda.h>
20 #include <sql-parser/gda-sql-parser.h>
21 #include <string.h>
22 
23 #define PROV_CLASS(provider) (GDA_SERVER_PROVIDER_CLASS (G_OBJECT_GET_CLASS (provider)))
24 
25 static gboolean
string_equal_to_template(const gchar * str,const gchar * tmpl)26 string_equal_to_template (const gchar *str, const gchar *tmpl)
27 {
28 	const gchar *ptrs, *ptrt;
29 	for (ptrs = str; *ptrs != '('; ptrs++);
30 
31 	for (ptrt = tmpl;
32 	     *ptrs && *ptrt;
33 	     ptrs++, ptrt++) {
34 		if (*ptrt == '@')
35 			continue;
36 		if (*ptrs != *ptrt)
37 			break;
38 	}
39 	if (*ptrs || *ptrt)
40 		return FALSE;
41 	else
42 		return TRUE;
43 }
44 
45 GdaTimestamp ts = {
46 	.year = 2013,
47 	.month = 8,
48 	.day = 28,
49 	.hour = 17,
50 	.minute = 10,
51 	.second = 23,
52 	.timezone = 3600 * 2
53 };
54 GdaTime gt = {
55 	.hour = 16,
56 	.minute = 9,
57 	.second = 22,
58 	.timezone = - 3600 * 3
59 };
60 
61 
62 static guint
do_a_test(GdaServerProvider * prov,GdaSqlParser * parser)63 do_a_test (GdaServerProvider *prov, GdaSqlParser *parser)
64 {
65 	guint nfailed = 0;
66 	GdaStatement *stmt;
67 	GdaSet *params;
68 	gchar *sql;
69 	GError *error = NULL;
70 
71 	/* SQL parsed as an INSERT statement */
72 	sql = "INSERT INTO tstest VALUES (##ts::timestamp, ##time::time)";
73 	stmt = gda_sql_parser_parse_string (parser, sql, NULL, &error);
74 	if (!stmt) {
75 		g_print ("Failed to parse [%s]: %s\n", sql, error && error->message ? error->message : "No detail");
76 		g_clear_error (&error);
77 		nfailed ++;
78 		goto endtest;
79 	}
80 
81 	g_assert (gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_INSERT);
82 	if (! gda_statement_get_parameters (stmt, &params, &error)) {
83 		g_print ("Failed to obtain parameters: %s\n", error && error->message ? error->message : "No detail");
84 		g_clear_error (&error);
85 		g_object_unref (stmt);
86 		nfailed ++;
87 		goto endtest;
88 	}
89 
90 	if (! gda_set_set_holder_value (params, &error, "ts", &ts)) {
91 		g_print ("Failed to bind 'ts' parameter: %s\n", error && error->message ? error->message : "No detail");
92 		g_clear_error (&error);
93 		g_object_unref (stmt);
94 		g_object_unref (params);
95 		nfailed ++;
96 		goto endtest;
97 	}
98 
99 	if (! gda_set_set_holder_value (params, &error, "time", &gt)) {
100 		g_print ("Failed to bind 'time' parameter: %s\n", error && error->message ? error->message : "No detail");
101 		g_clear_error (&error);
102 		g_object_unref (stmt);
103 		g_object_unref (params);
104 		nfailed ++;
105 		goto endtest;
106 	}
107 
108 	gchar *expected;
109 	expected = "('@@@@@@@@@@ 17:10:23+2', '16:09:22-3')";
110 	if (prov && PROV_CLASS (prov)->statement_to_sql)
111 		sql = PROV_CLASS (prov)->statement_to_sql (prov, NULL, stmt, params, 0, NULL, &error);
112 	else
113 		sql = gda_statement_to_sql_extended (stmt, NULL, params, 0, NULL, &error);
114 	if (!sql) {
115 		g_print ("Failed to render as SQL: %s\n", error && error->message ? error->message : "No detail");
116 		g_clear_error (&error);
117 		g_object_unref (stmt);
118 		g_object_unref (params);
119 		nfailed ++;
120 		goto endtest;
121 	}
122 	if (!string_equal_to_template (sql, expected)) {
123 		g_print ("Wrong rendered SQL: [%s] instead of [%s]\n", sql, expected);
124 		g_object_unref (stmt);
125 		g_object_unref (params);
126 		g_free (sql);
127 		nfailed ++;
128 		goto endtest;
129 	}
130 	g_free (sql);
131 
132 	expected = "('@@@@@@@@@@ 15:10:23', '19:09:22')";
133 	if (prov && PROV_CLASS (prov)->statement_to_sql)
134 		sql = PROV_CLASS (prov)->statement_to_sql (prov, NULL, stmt, params, GDA_STATEMENT_SQL_TIMEZONE_TO_GMT, NULL, &error);
135 	else
136 		sql = gda_statement_to_sql_extended (stmt, NULL, params, GDA_STATEMENT_SQL_TIMEZONE_TO_GMT, NULL, &error);
137 	if (!sql) {
138 		g_print ("Failed to render as SQL: %s\n", error && error->message ? error->message : "No detail");
139 		g_clear_error (&error);
140 		g_object_unref (stmt);
141 		g_object_unref (params);
142 		nfailed ++;
143 		goto endtest;
144 	}
145 	if (!string_equal_to_template (sql, expected)) {
146 		g_print ("Wrong rendered SQL for GMT timezone: [%s] instead of [%s]\n", sql, expected);
147 		g_object_unref (stmt);
148 		g_object_unref (params);
149 		g_free (sql);
150 		nfailed ++;
151 		goto endtest;
152 	}
153 	g_free (sql);
154 
155 	/* SQL not parsed as a valid statement */
156 	sql = "AAAA (##ts::timestamp, ##time::time)";
157 	stmt = gda_sql_parser_parse_string (parser, sql, NULL, &error);
158 	if (!stmt) {
159 		g_print ("Failed to parse [%s]: %s\n", sql, error && error->message ? error->message : "No detail");
160 		g_clear_error (&error);
161 		nfailed ++;
162 		goto endtest;
163 	}
164 
165 	g_assert (gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_UNKNOWN);
166 	if (! gda_statement_get_parameters (stmt, &params, &error)) {
167 		g_print ("Failed to obtain parameters: %s\n", error && error->message ? error->message : "No detail");
168 		g_clear_error (&error);
169 		g_object_unref (stmt);
170 		nfailed ++;
171 		goto endtest;
172 	}
173 
174 	if (! gda_set_set_holder_value (params, &error, "ts", &ts)) {
175 		g_print ("Failed to bind 'ts' parameter: %s\n", error && error->message ? error->message : "No detail");
176 		g_clear_error (&error);
177 		g_object_unref (stmt);
178 		g_object_unref (params);
179 		nfailed ++;
180 		goto endtest;
181 	}
182 
183 	if (! gda_set_set_holder_value (params, &error, "time", &gt)) {
184 		g_print ("Failed to bind 'time' parameter: %s\n", error && error->message ? error->message : "No detail");
185 		g_clear_error (&error);
186 		g_object_unref (stmt);
187 		g_object_unref (params);
188 		nfailed ++;
189 		goto endtest;
190 	}
191 
192 	expected = "('@@@@@@@@@@ 17:10:23+2', '16:09:22-3')";
193 	if (prov && PROV_CLASS (prov)->statement_to_sql)
194 		sql = PROV_CLASS (prov)->statement_to_sql (prov, NULL, stmt, params, 0, NULL, &error);
195 	else
196 		sql = gda_statement_to_sql_extended (stmt, NULL, params, 0, NULL, &error);
197 	if (!sql) {
198 		g_print ("Failed to render as SQL: %s\n", error && error->message ? error->message : "No detail");
199 		g_clear_error (&error);
200 		g_object_unref (stmt);
201 		g_object_unref (params);
202 		nfailed ++;
203 		goto endtest;
204 	}
205 	if (!string_equal_to_template (sql, expected)) {
206 		g_print ("Wrong rendered SQL: [%s] instead of [%s]\n", sql, expected);
207 		g_object_unref (stmt);
208 		g_object_unref (params);
209 		g_free (sql);
210 		nfailed ++;
211 		goto endtest;
212 	}
213 	g_free (sql);
214 
215 	expected = "('@@@@@@@@@@ 15:10:23', '19:09:22')";
216 	if (prov && PROV_CLASS (prov)->statement_to_sql)
217 		sql = PROV_CLASS (prov)->statement_to_sql (prov, NULL, stmt, params, GDA_STATEMENT_SQL_TIMEZONE_TO_GMT, NULL, &error);
218 	else
219 		sql = gda_statement_to_sql_extended (stmt, NULL, params, GDA_STATEMENT_SQL_TIMEZONE_TO_GMT, NULL, &error);
220 	if (!sql) {
221 		g_print ("Failed to render as SQL: %s\n", error && error->message ? error->message : "No detail");
222 		g_clear_error (&error);
223 		g_object_unref (stmt);
224 		g_object_unref (params);
225 		nfailed ++;
226 		goto endtest;
227 	}
228 	if (!string_equal_to_template (sql, expected)) {
229 		g_print ("Wrong rendered SQL for GMT timezone: [%s] instead of [%s]\n", sql, expected);
230 		g_object_unref (stmt);
231 		g_object_unref (params);
232 		g_free (sql);
233 		nfailed ++;
234 		goto endtest;
235 	}
236 	g_free (sql);
237 
238  endtest:
239 	return nfailed;
240 }
241 
242 int
main(int argc,char ** argv)243 main (int argc, char** argv)
244 {
245 	gchar *file;
246 	GError *error = NULL;
247 	GdaDataModel *model;
248 	guint i, nrows;
249 	guint nfailed = 0;
250 	gda_init ();
251 
252 	/* generic parser */
253 	GdaSqlParser *parser;
254 	parser = gda_sql_parser_new ();
255 	nfailed += do_a_test (NULL, parser);
256 	g_object_unref (parser);
257 
258 	/* test other parsers only if generic one is Ok */
259 	if (nfailed == 0) {
260 		model = gda_config_list_providers ();
261 		nrows = gda_data_model_get_n_rows (model);
262 		for (i = 0; i < nrows; i++) {
263 			const GValue *cvalue;
264 			cvalue = gda_data_model_get_value_at (model, 0, i, NULL);
265 			g_assert (cvalue && (G_VALUE_TYPE (cvalue) == G_TYPE_STRING));
266 			if (!g_ascii_strcasecmp (g_value_get_string (cvalue), "Oracle"))
267 				continue; /* ignore Oracle for now */
268 			g_print ("Testing database provider '%s'\n", g_value_get_string (cvalue));
269 
270 			GdaServerProvider *prov;
271 			prov = gda_config_get_provider (g_value_get_string (cvalue), NULL);
272 			g_assert (prov);
273 
274 			GdaSqlParser *parser;
275 			parser = gda_server_provider_create_parser (prov, NULL);
276 			if (!parser)
277 				parser = gda_sql_parser_new ();
278 
279 			nfailed += do_a_test (prov, parser);
280 			g_object_unref (parser);
281 		}
282 		g_object_unref (model);
283 	}
284 
285 	if (nfailed == 0) {
286 		g_print ("Ok\n");
287 		return EXIT_SUCCESS;
288 	}
289 	else {
290 		g_print ("%u failed\n", nfailed);
291 		return EXIT_FAILURE;
292 	}
293 }
294