1 /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004  Brian Bruns
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library 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 GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 
20 /*
21  * Purpose: test conversions.  If they work, test their performance.
22  * To test performance, call this program with an iteration count (10 is probably fine).
23  * The following shows performance converting to varchar:
24  * $ make convert && ./convert 1 |grep iterations |grep 'varchar\.' |sort -n
25  */
26 #include "common.h"
27 #include <freetds/convert.h>
28 #include "replacements.h"
29 
30 #include <freetds/time.h>
31 
32 #include <common/test_assert.h>
33 
34 static int g_result = 0;
35 static TDSCONTEXT *ctx;
36 
37 static void
free_convert(int type,CONV_RESULT * cr)38 free_convert(int type, CONV_RESULT *cr)
39 {
40 	switch (type) {
41 	case SYBCHAR: case SYBVARCHAR: case SYBTEXT: case XSYBCHAR: case XSYBVARCHAR:
42         case SYBNVARCHAR: case SYBNTEXT: case XSYBNCHAR: case XSYBNVARCHAR:
43 	case SYBBINARY: case SYBVARBINARY: case SYBIMAGE: case XSYBBINARY: case XSYBVARBINARY:
44 	case SYBLONGBINARY:
45 		free(cr->c);
46 		break;
47 	}
48 }
49 
50 int
main(int argc,char ** argv)51 main(int argc, char **argv)
52 {
53 	int srctype;
54 	int desttype;
55 
56 	/* some default inputs */
57 	static const int bit_input = 1;
58 
59 	/* timing variables to compute performance */
60 	struct timeval start, end;
61 	double starttime, endtime;
62 
63 	int i, j, iterations = 0, result;
64 
65 	TDS_CHAR *src = NULL;
66         TDS_SMALLINT widesrc[40];
67 	TDS_UINT srclen;
68 	CONV_RESULT cr;
69 
70 	TDS_NUMERIC numeric;
71 	TDS_MONEY money;
72 	TDS_MONEY4 money4;
73 	TDS_DATETIME datetime;
74 	TDS_DATETIME4 datetime4;
75 	TDS_DATETIMEALL dta;
76 	TDS_DATE date;
77 	TDS_TIME time;
78 	TDS_BIGDATETIME bigdatetime;
79 	TDS_BIGTIME bigtime;
80 
81 	TDS_TINYINT tds_tinyint;
82 	TDS_SMALLINT tds_smallint;
83 	TDS_INT tds_int;
84 	TDS_INT8 tds_int8;
85 	TDS_USMALLINT tds_usmallint;
86 	TDS_UINT tds_uint;
87 	TDS_UINT8 tds_uint8;
88 
89 	TDS_REAL tds_real;
90 	TDS_FLOAT tds_float;
91 
92 	TDS_UNIQUE tds_unique;
93 
94 	if (argc > 1) {
95 		iterations = atoi(argv[1]);
96 		printf("Computing %d iterations\n", iterations);
97 	}
98 
99 	setbuf(stdout, NULL);
100 	setbuf(stderr, NULL);
101 
102 	ctx = tds_alloc_context(NULL);
103 	assert(ctx);
104 	if (ctx->locale && !ctx->locale->date_fmt) {
105 		/* set default in case there's no locale file */
106 		ctx->locale->date_fmt = strdup(STD_DATETIME_FMT);
107 	}
108 
109 
110 	/*
111 	 * Test every possible conversion pair
112 	 */
113 	for (i = 0; i < 0x10000; i++) {
114 		srctype  = i >> 8;
115 		desttype = i & 0xff;
116 		srctype = (srctype + SYBCHAR) & 0xff;
117 
118 		if (!tds_willconvert(srctype, desttype)) {
119 			/* pass a CONV_RESULT as input for make sure size and alignment is enough
120 			 * for all types */
121 			CONV_RESULT src;
122 
123 			memset(&src, 0, sizeof(src));
124 			srclen = 4;
125 			result = tds_convert(ctx, srctype, (const TDS_CHAR *) &src, srclen, desttype, &cr);
126 			if (result >= 0)
127 				free_convert(desttype, &cr);
128 			if (result != TDS_CONVERT_NOAVAIL) {
129 				printf("NOT EXPECTED: converted %d (%s, %d bytes) : %d (%s, %d bytes).\n",
130 				       srctype, tds_prtype(srctype), srclen,
131 				       desttype, tds_prtype(desttype), result);
132 				exit(1);
133 			}
134 			continue;	/* don't attempt nonconvertible types */
135 		}
136 
137 		if (srctype == desttype)
138 			continue;	/* don't attempt same types */
139 
140 		/* valid types should have a name ! */
141 		assert(tds_prtype(srctype)[0] != 0);
142 		assert(tds_prtype(desttype)[0] != 0);
143 
144 		cr.n.precision = 8;
145 		cr.n.scale = 2;
146 
147 		switch (srctype) {
148 		case SYBCHAR:
149 		case SYBVARCHAR:
150 		case SYBTEXT:
151 		case SYBBINARY:
152 		case SYBVARBINARY:
153 		case SYBIMAGE:
154 		case SYBLONGBINARY:
155 		case XSYBBINARY:
156 		case XSYBVARBINARY:
157 		case XSYBCHAR:
158 		case XSYBVARCHAR:
159                 case SYBNTEXT:
160                 case SYBNVARCHAR:
161                 case XSYBNCHAR:
162                 case XSYBNVARCHAR:
163 			switch (desttype) {
164 			case SYBCHAR:
165 			case SYBVARCHAR:
166 			case SYBTEXT:
167                         case SYBNTEXT:
168                         case SYBNVARCHAR:
169                         case XSYBNCHAR:
170                         case XSYBNVARCHAR:
171 			case SYBDATETIME:
172 			case SYBDATETIME4:
173 				src = "Jan  1, 1999";
174 				break;
175 			case SYBMSDATE:
176 			case SYBMSDATETIME2:
177 			case SYBMSDATETIMEOFFSET:
178 			case SYBDATE:
179 				src = "2012-11-27";
180 				break;
181 			case SYBMSTIME:
182 			case SYBTIME:
183 				src = "15:27:12";
184 				break;
185 			case SYB5BIGTIME:
186 				src = "15:27:12.327862";
187 				break;
188 			case SYB5BIGDATETIME:
189 				src = "2015-09-12 21:48:12.638161";
190 				break;
191 			case SYBBINARY:
192 			case SYBIMAGE:
193 				src = "0xbeef";
194 				break;
195 			case SYBINT1:
196 			case SYBINT2:
197 			case SYBINT4:
198 			case SYBINT8:
199 			case SYBUINT1:
200 			case SYBUINT2:
201 			case SYBUINT4:
202 			case SYBUINT8:
203 				src = "255";
204 				break;
205 			case SYBFLT8:
206 			case SYBREAL:
207 			case SYBNUMERIC:
208 			case SYBDECIMAL:
209 			case SYBMONEY:
210 			case SYBMONEY4:
211 				src = "1999.25";
212 				cr.n.precision = 8;
213 				cr.n.scale = 2;
214 				break;
215 			case SYBUNIQUE:
216 				src = "A8C60F70-5BD4-3E02-B769-7CCCCA585DCC";
217 				break;
218 			case SYBBIT:
219 			default:
220 				src = "1";
221 				break;
222 			}
223 			assert(src);
224                         srclen = (TDS_UINT) strlen(src);
225                         if (srctype == SYBNTEXT  ||  srctype == SYBNVARCHAR
226                             ||  srctype == XSYBNCHAR
227                             ||  srctype == XSYBNVARCHAR) {
228                                 assert(srclen * sizeof(*widesrc)
229                                        < sizeof(widesrc));
230                                 for (j = 0;  j <= srclen;  ++j) {
231                                         widesrc[j] = src[j];
232                                 }
233                                 src = (char *) widesrc;
234                                 srclen *= sizeof(*widesrc);
235                         }
236 			break;
237 		case SYBINT1:
238 		case SYBUINT1:
239 			src = (char *) &tds_tinyint;
240 			srclen = sizeof(tds_tinyint);
241 			break;
242 		case SYBINT2:
243 			src = (char *) &tds_smallint;
244 			srclen = sizeof(tds_smallint);
245 			break;
246 		case SYBINT4:
247 			src = (char *) &tds_int;
248 			srclen = sizeof(tds_int);
249 			break;
250 		case SYBINT8:
251 			src = (char *) &tds_int8;
252 			srclen = sizeof(tds_int8);
253 			break;
254 		case SYBUINT2:
255 			src = (char *) &tds_usmallint;
256 			srclen = sizeof(tds_usmallint);
257 			break;
258 		case SYBUINT4:
259 			src = (char *) &tds_uint;
260 			srclen = sizeof(tds_uint);
261 			break;
262 		case SYBUINT8:
263 			src = (char *) &tds_uint8;
264 			srclen = sizeof(tds_uint8);
265 			break;
266 		case SYBFLT8:
267 			tds_float = 3.14159;
268 			src = (char *) &tds_float;
269 			srclen = sizeof(tds_float);
270 			break;
271 		case SYBREAL:
272 			tds_real = (TDS_REAL) 3.14159;
273 			src = (char *) &tds_real;
274 			srclen = sizeof(tds_real);
275 			break;
276 		case SYBNUMERIC:
277 		case SYBDECIMAL:
278 			src = (char *) &numeric;
279 			srclen = sizeof(numeric);
280 			break;
281 		case SYBMONEY:
282 			src = (char *) &money;
283 			srclen = sizeof(money);
284 			break;
285 		case SYBMONEY4:
286 			src = (char *) &money4;
287 			srclen = sizeof(money4);
288 			break;
289 		case SYBBIT:
290 		case SYBBITN:
291 			src = (char *) &bit_input;
292 			srclen = sizeof(bit_input);
293 			break;
294 		case SYBDATETIME:
295 			src = (char *) &datetime;
296 			srclen = sizeof(datetime);
297 			break;
298 		case SYBDATETIME4:
299 			src = (char *) &datetime4;
300 			srclen = sizeof(datetime4);
301 			break;
302 		case SYBDATE:
303 			src = (char *) &date;
304 			srclen = sizeof(date);
305 			break;
306 		case SYBTIME:
307 			src = (char *) &time;
308 			srclen = sizeof(time);
309 			break;
310 		case SYB5BIGTIME:
311 			src = (char *) &bigtime;
312 			srclen = sizeof(bigtime);
313 			break;
314 		case SYB5BIGDATETIME:
315 			src = (char *) &bigdatetime;
316 			srclen = sizeof(bigdatetime);
317 			break;
318 		case SYBUNIQUE:
319 			src = (char *) &tds_unique;
320 			srclen = sizeof(tds_unique);
321 			break;
322 		case SYBMSTIME:
323 		case SYBMSDATE:
324 		case SYBMSDATETIME2:
325 		case SYBMSDATETIMEOFFSET:
326 			src = (char *) &dta;
327 			srclen = sizeof(dta);
328 			break;
329 		/*****  not defined yet
330 			case SYBBOUNDARY:
331 			case SYBSENSITIVITY:
332 				fprintf (stderr, "type %d not supported\n", srctype );
333 				continue;
334 				break;
335 		*****/
336 		default:
337 			fprintf(stderr, "no such type %d (%s)\n", srctype, tds_prtype(srctype));
338 			return -1;
339 		}
340 
341 		/*
342 		 * Now at last do the conversion
343 		 */
344 
345 		result = tds_convert(ctx, srctype, src, srclen, desttype, &cr);
346                 /* if (result >= 0) */
347 			free_convert(desttype, &cr);
348 
349 		if (result < 0) {
350 			if (result == TDS_CONVERT_NOAVAIL)	/* tds_willconvert returned true, but it lied. */
351 				fprintf(stderr, "Conversion not yet implemented:\n\t");
352 
353 			fprintf(stderr, "failed (%d) to convert %d (%s, %d bytes) : %d (%s).\n",
354 				result,
355 				srctype, tds_prtype(srctype), srclen,
356 				desttype, tds_prtype(desttype));
357 
358 			if (result == TDS_CONVERT_NOAVAIL)
359 				exit(1);
360 		}
361 
362 		printf("converted %d (%s, %d bytes) -> %d (%s, %d bytes).\n",
363 		       srctype, tds_prtype(srctype), srclen,
364 		       desttype, tds_prtype(desttype), result);
365 
366 		/*
367 		 * In the first iteration, start with varchar -> others.
368 		 * By saving the output, we initialize subsequent inputs.
369 		 */
370 
371 		switch (desttype) {
372 		case SYBNUMERIC:
373 		case SYBDECIMAL:
374 			numeric = cr.n;
375 			break;
376 		case SYBMONEY:
377 			money = cr.m;
378 			break;
379 		case SYBMONEY4:
380 			money4 = cr.m4;
381 			break;
382 		case SYBDATETIME:
383 			datetime = cr.dt;
384 			break;
385 		case SYBDATETIME4:
386 			datetime4 = cr.dt4;
387 			break;
388 		case SYBDATE:
389 			date = cr.date;
390 			break;
391 		case SYBTIME:
392 			time = cr.time;
393 			break;
394 		case SYBMSDATETIME2:
395 			dta = cr.dta;
396 			break;
397 		case SYB5BIGTIME:
398 			bigtime = cr.bigtime;
399 			break;
400 		case SYB5BIGDATETIME:
401 			bigdatetime = cr.bigdatetime;
402 			break;
403 		case SYBINT1:
404 		case SYBUINT1:
405 			tds_tinyint = cr.ti;
406 			break;
407 		case SYBINT2:
408 			tds_smallint = cr.si;
409 			break;
410 		case SYBINT4:
411 			tds_int = cr.i;
412 			break;
413 		case SYBINT8:
414 			tds_int8 = cr.bi;
415 			break;
416 		case SYBUINT2:
417 			tds_usmallint = cr.usi;
418 			break;
419 		case SYBUINT4:
420 			tds_uint = cr.ui;
421 			break;
422 		case SYBUINT8:
423 			tds_uint8 = cr.ubi;
424 			break;
425 		case SYBUNIQUE:
426 			tds_unique = cr.u;
427 			break;
428 		default:
429 			break;
430 		}
431 
432 		/*
433 		 * If an iteration count was passed on the command line (not by "make check")
434 		 * run the conversion N times and print the conversions per second.
435 		 */
436 		result = gettimeofday(&start, NULL);
437 		starttime = (double) start.tv_sec + (double) start.tv_usec * 0.000001;
438 
439 		for (j = 0; result >= 0 && j < iterations; j++) {
440 			result = tds_convert(ctx, srctype, src, srclen, desttype, &cr);
441 			if (result >= 0)
442 				free_convert(desttype, &cr);
443 		}
444 		if (result < 0)
445 			continue;
446 
447 		result = gettimeofday(&end, NULL);
448 		endtime = (double) end.tv_sec + (double) end.tv_usec * 0.000001;
449 
450 		if (endtime != starttime) {
451 			printf("%9.0f iterations/second converting %13s => %s.\n",
452 				j / (endtime - starttime), tds_prtype(srctype), tds_prtype(desttype));
453 		}
454 
455 	}
456 	tds_free_context(ctx);
457 
458 	return g_result;
459 }
460