1 /*
2  * Test reading data with SQLGetData
3  */
4 #include "common.h"
5 #include <assert.h>
6 
7 static void
test_err(const char * data,int c_type,const char * state)8 test_err(const char *data, int c_type, const char *state)
9 {
10 	char sql[128];
11 	SQLLEN ind;
12 	const unsigned int buf_size = 128;
13 	char *buf = (char *) malloc(buf_size);
14 
15 	sprintf(sql, "SELECT '%s'", data);
16 	odbc_command(sql);
17 	SQLFetch(odbc_stmt);
18 	CHKGetData(1, c_type, buf, buf_size, &ind, "E");
19 	free(buf);
20 	odbc_read_error();
21 	if (strcmp(odbc_sqlstate, state) != 0) {
22 		fprintf(stderr, "Unexpected sql state returned\n");
23 		odbc_disconnect();
24 		exit(1);
25 	}
26 	odbc_reset_statement();
27 }
28 
29 static int lc;
30 static int type;
31 
32 static int
mycmp(const char * s1,const char * s2)33 mycmp(const char *s1, const char *s2)
34 {
35 	SQLWCHAR buf[128], *wp;
36 	unsigned l;
37 
38 	if (type == SQL_C_CHAR)
39 		return strcmp(s1, s2);
40 
41 	l = strlen(s2);
42 	assert(l < TDS_VECTOR_SIZE(buf));
43 	wp = buf;
44 	do {
45 		*wp++ = *s2;
46 	} while (*s2++);
47 
48 	return memcmp(s1, buf, l * lc + lc);
49 }
50 
51 static void
test_split(const char * n_flag)52 test_split(const char *n_flag)
53 {
54 #define CheckLen(x) do { \
55 	if (len != (x)) { \
56 		fprintf(stderr, "Wrong len %ld at line %d expected %d\n", (long int) len, __LINE__, (x)); \
57 		exit(1); \
58 	} \
59 	} while(0)
60 
61 	char *sql;
62 	char *buf = NULL;
63 	const char *collate = "";
64 	SQLLEN len;
65 
66 	/* TODO test with VARCHAR too */
67 	if (odbc_db_is_microsoft())
68 		collate = " COLLATE Latin1_General_CI_AS";
69 	sql = odbc_buf_asprintf(&odbc_buf, "SELECT CONVERT(%sTEXT,'Prova'%s + REPLICATE('x',500))%s", n_flag, collate, collate);
70 	odbc_command(sql);
71 
72 	CHKFetch("S");
73 
74 	/* these 2 tests test an old severe BUG in FreeTDS */
75 	buf = (char *) ODBC_GET(1);
76 	CHKGetData(1, type, buf, 0, &len, "I");
77 	if (len != SQL_NO_TOTAL)
78 		CheckLen(505*lc);
79 	CHKGetData(1, type, buf, 0, &len, "I");
80 	if (len != SQL_NO_TOTAL)
81 		CheckLen(505*lc);
82 	buf = (char *) ODBC_GET(3*lc);
83 	CHKGetData(1, type, buf, 3 * lc, &len, "I");
84 	if (len != SQL_NO_TOTAL)
85 		CheckLen(505*lc);
86 	if (mycmp(buf, "Pr") != 0) {
87 		printf("Wrong data result 1\n");
88 		exit(1);
89 	}
90 
91 	buf = (char *) ODBC_GET(16*lc);
92 	CHKGetData(1, type, buf, 16 * lc, &len, "I");
93 	if (len != SQL_NO_TOTAL)
94 		CheckLen(503*lc);
95 	if (mycmp(buf, "ovaxxxxxxxxxxxx") != 0) {
96 		printf("Wrong data result 2 res = '%s'\n", buf);
97 		exit(1);
98 	}
99 
100 	buf = (char *) ODBC_GET(256*lc);
101 	CHKGetData(1, type, buf, 256 * lc, &len, "I");
102 	if (len != SQL_NO_TOTAL)
103 		CheckLen(488*lc);
104 	CHKGetData(1, type, buf, 256 * lc, &len, "S");
105 	CheckLen(233*lc);
106 	CHKGetData(1, type, buf, 256 * lc, &len, "No");
107 
108 	odbc_reset_statement();
109 
110 	/* test with varchar, not blob but variable */
111 	sql = odbc_buf_asprintf(&odbc_buf, "SELECT CONVERT(%sVARCHAR(100), 'Other test')", n_flag);
112 	odbc_command(sql);
113 
114 	CHKFetch("S");
115 
116 	buf = (char *) ODBC_GET(7*lc);
117 	CHKGetData(1, type, buf, 7 * lc, NULL, "I");
118 	if (mycmp(buf, "Other ") != 0) {
119 		printf("Wrong data result 1\n");
120 		exit(1);
121 	}
122 
123 	buf = (char *) ODBC_GET(5*lc);
124 	CHKGetData(1, type, buf, 20, NULL, "S");
125 	if (mycmp(buf, "test") != 0) {
126 		printf("Wrong data result 2 res = '%s'\n", buf);
127 		exit(1);
128 	}
129 	ODBC_FREE();
130 
131 	odbc_reset_statement();
132 }
133 
134 int
main(int argc,char * argv[])135 main(int argc, char *argv[])
136 {
137 	char buf[32];
138 	SQLINTEGER int_buf;
139 	SQLLEN len;
140 	SQLRETURN rc;
141 	TIMESTAMP_STRUCT tss;
142 
143 	odbc_connect();
144 
145 	lc = 1;
146 	type = SQL_C_CHAR;
147 	test_split("");
148 
149 	lc = sizeof(SQLWCHAR);
150 	type = SQL_C_WCHAR;
151 	test_split("");
152 
153 	if (odbc_db_is_microsoft() && odbc_db_version_int() >= 0x07000000u) {
154 		lc = 1;
155 		type = SQL_C_CHAR;
156 		test_split("N");
157 
158 		lc = sizeof(SQLWCHAR);
159 		type = SQL_C_WCHAR;
160 		test_split("N");
161 	}
162 
163 	/* test with fixed length */
164 	odbc_command("SELECT CONVERT(INT, 12345)");
165 
166 	CHKFetch("S");
167 
168 	int_buf = 0xdeadbeef;
169 	CHKGetData(1, SQL_C_SLONG, &int_buf, 0, NULL, "S");
170 	if (int_buf != 12345) {
171 		printf("Wrong data result\n");
172 		exit(1);
173 	}
174 
175 	CHKGetData(1, SQL_C_SLONG, &int_buf, 0, NULL, "No");
176 	if (int_buf != 12345) {
177 		printf("Wrong data result 2 res = %d\n", (int) int_buf);
178 		exit(1);
179 	}
180 
181 	odbc_reset_statement();
182 
183 	/* test with numeric */
184 	odbc_command("SELECT CONVERT(NUMERIC(18,5), 1850000000000)");
185 
186 	CHKFetch("S");
187 
188 	memset(buf, 'x', sizeof(buf));
189 	CHKGetData(1, SQL_C_CHAR, buf, 14, NULL, "S");
190 	buf[sizeof(buf)-1] = 0;
191 	if (strcmp(buf, "1850000000000") != 0) {
192 		printf("Wrong data result: %s\n", buf);
193 		exit(1);
194 	}
195 
196 	/* should give NO DATA */
197 	CHKGetData(1, SQL_C_CHAR, buf, 14, NULL, "No");
198 	buf[sizeof(buf)-1] = 0;
199 	if (strcmp(buf, "1850000000000") != 0) {
200 		printf("Wrong data result 3 res = %s\n", buf);
201 		exit(1);
202 	}
203 
204 	odbc_reset_statement();
205 
206 
207 	/* test int to truncated string */
208 	odbc_command("SELECT CONVERT(INTEGER, 12345)");
209 	CHKFetch("S");
210 
211 	/* error 22003 */
212 	memset(buf, 'x', sizeof(buf));
213 	CHKGetData(1, SQL_C_CHAR, buf, 4, NULL, "E");
214 #ifdef ENABLE_DEVELOPING
215 	buf[4] = 0;
216 	if (strcmp(buf, "xxxx") != 0) {
217 		fprintf(stderr, "Wrong buffer result buf = %s\n", buf);
218 		exit(1);
219 	}
220 #endif
221 	odbc_read_error();
222 	if (strcmp(odbc_sqlstate, "22003") != 0) {
223 		fprintf(stderr, "Unexpected sql state %s returned\n", odbc_sqlstate);
224 		odbc_disconnect();
225 		exit(1);
226 	}
227 	CHKGetData(1, SQL_C_CHAR, buf, 2, NULL, "No");
228 	odbc_reset_statement();
229 
230 	/* test unique identifier to truncated string */
231 	rc = odbc_command2("SELECT CONVERT(UNIQUEIDENTIFIER, 'AA7DF450-F119-11CD-8465-00AA00425D90')", "SENo");
232 	if (rc != SQL_ERROR) {
233 		CHKFetch("S");
234 
235 		/* error 22003 */
236 		CHKGetData(1, SQL_C_CHAR, buf, 17, NULL, "E");
237 		odbc_read_error();
238 		if (strcmp(odbc_sqlstate, "22003") != 0) {
239 			fprintf(stderr, "Unexpected sql state %s returned\n", odbc_sqlstate);
240 			odbc_disconnect();
241 			exit(1);
242 		}
243 		CHKGetData(1, SQL_C_CHAR, buf, 2, NULL, "No");
244 	}
245 	odbc_reset_statement();
246 
247 
248 	odbc_disconnect();
249 
250 	odbc_use_version3 = 1;
251 	odbc_connect();
252 
253 	/* test error from SQLGetData */
254 	/* wrong constant, SQL_VARCHAR is invalid as C type */
255 	test_err("prova 123",           SQL_VARCHAR,     "HY003");
256 	/* use ARD but no ARD data column */
257 	test_err("prova 123",           SQL_ARD_TYPE,    "07009");
258 	/* wrong conversion, int */
259 	test_err("prova 123",           SQL_C_LONG,      "22018");
260 	/* wrong conversion, date */
261 	test_err("prova 123",           SQL_C_TIMESTAMP, "22018");
262 	/* overflow */
263 	test_err("1234567890123456789", SQL_C_LONG,      "22003");
264 
265 	/* test datetime precision */
266 	odbc_command("SELECT CONVERT(DATETIME, '2018-08-15 12:34:56.007')");
267 
268 	CHKFetch("S");
269 
270 	memset(&tss, 'x', sizeof(tss));
271 	CHKGetData(1, SQL_C_TYPE_TIMESTAMP, &tss, sizeof(tss), NULL, "S");
272 	if (tss.fraction != 7000000) {
273 		printf("Wrong data result: %lu\n", (unsigned long) tss.fraction);
274 		exit(1);
275 	}
276 
277 	odbc_reset_statement();
278 
279 	/* test for empty string from mssql */
280 	if (odbc_db_is_microsoft()) {
281 		lc = 1;
282 		type = SQL_C_CHAR;
283 
284 		for (;;) {
285 			void *buf = ODBC_GET(lc);
286 
287 			odbc_command("SELECT CONVERT(TEXT,'' COLLATE Latin1_General_CI_AS)");
288 
289 			CHKFetch("S");
290 
291 			len = 1234;
292 			CHKGetData(1, type, buf, lc, &len, "S");
293 
294 			if (len != 0) {
295 				fprintf(stderr, "Wrong len returned, returned %ld\n", (long) len);
296 				return 1;
297 			}
298 
299 			CHKGetData(1, type, buf, lc, NULL, "No");
300 			odbc_reset_statement();
301 			ODBC_FREE();
302 
303 			buf = ODBC_GET(4096*lc);
304 
305 			odbc_command("SELECT CONVERT(TEXT,'' COLLATE Latin1_General_CI_AS)");
306 
307 			CHKFetch("S");
308 
309 			len = 1234;
310 			CHKGetData(1, type, buf, lc*4096, &len, "S");
311 
312 			if (len != 0) {
313 				fprintf(stderr, "Wrong len returned, returned %ld\n", (long) len);
314 				return 1;
315 			}
316 
317 			CHKGetData(1, type, buf, lc*4096, NULL, "No");
318 			odbc_reset_statement();
319 			ODBC_FREE();
320 
321 			if (type != SQL_C_CHAR)
322 				break;
323 			lc = sizeof(SQLWCHAR);
324 			type = SQL_C_WCHAR;
325 		}
326 
327 		odbc_command("SELECT CONVERT(TEXT,'' COLLATE Latin1_General_CI_AS)");
328 
329 		CHKFetch("S");
330 
331 		len = 1234;
332 		CHKGetData(1, SQL_C_BINARY, buf, 1, &len, "S");
333 
334 		if (len != 0) {
335 			fprintf(stderr, "Wrong len returned, returned %ld\n", (long) len);
336 			return 1;
337 		}
338 
339 		CHKGetData(1, SQL_C_BINARY, buf, 1, NULL, "No");
340 	}
341 
342 	odbc_disconnect();
343 
344 	printf("Done.\n");
345 	return 0;
346 }
347