Line data Source code
1 : #include "common.h"
2 : #include <ctype.h>
3 : #include "parser.h"
4 : #include <odbcss.h>
5 : #include <freetds/bool.h>
6 :
7 : /*
8 : * SQLDescribeCol test for precision
9 : * test what say SQLDescribeCol about precision using some type
10 : */
11 :
12 : static int g_result = 0;
13 :
14 : static int
15 3188 : get_int(const char *s, odbc_parser *parser)
16 : {
17 : char *end;
18 : long l;
19 :
20 3188 : if (!s)
21 0 : odbc_fatal(parser, ": NULL int\n");
22 3188 : l = strtol(s, &end, 0);
23 3188 : if (end[0])
24 0 : odbc_fatal(parser, ": Invalid int\n");
25 3188 : return (int) l;
26 : }
27 :
28 : struct lookup_int
29 : {
30 : const char *name;
31 : int value;
32 : };
33 :
34 : static int
35 3444 : lookup(const char *name, const struct lookup_int *table, odbc_parser *parser)
36 : {
37 3444 : if (!table)
38 3180 : return get_int(name, parser);
39 :
40 3070 : for (; table->name; ++table)
41 3334 : if (strcmp(table->name, name) == 0)
42 264 : return table->value;
43 :
44 0 : return get_int(name, parser);
45 : }
46 :
47 : static const char*
48 0 : unlookup(long int value, const struct lookup_int *table)
49 : {
50 : static char buf[32];
51 :
52 0 : sprintf(buf, "%ld", value);
53 0 : if (!table)
54 : return buf;
55 :
56 0 : for (; table->name; ++table)
57 0 : if (table->value == value)
58 : return table->name;
59 :
60 : return buf;
61 : }
62 :
63 :
64 : static struct lookup_int sql_types[] = {
65 : #define TYPE(s) { #s, s }
66 : TYPE(SQL_CHAR),
67 : TYPE(SQL_VARCHAR),
68 : TYPE(SQL_LONGVARCHAR),
69 : TYPE(SQL_WCHAR),
70 : TYPE(SQL_WVARCHAR),
71 : TYPE(SQL_WLONGVARCHAR),
72 : TYPE(SQL_DECIMAL),
73 : TYPE(SQL_NUMERIC),
74 : TYPE(SQL_SMALLINT),
75 : TYPE(SQL_INTEGER),
76 : TYPE(SQL_REAL),
77 : TYPE(SQL_FLOAT),
78 : TYPE(SQL_DOUBLE),
79 : TYPE(SQL_BIT),
80 : TYPE(SQL_TINYINT),
81 : TYPE(SQL_BIGINT),
82 : TYPE(SQL_BINARY),
83 : TYPE(SQL_VARBINARY),
84 : TYPE(SQL_LONGVARBINARY),
85 : TYPE(SQL_DATE),
86 : TYPE(SQL_TIME),
87 : TYPE(SQL_TIMESTAMP),
88 : TYPE(SQL_TYPE_DATE),
89 : TYPE(SQL_TYPE_TIME),
90 : TYPE(SQL_TYPE_TIMESTAMP),
91 : TYPE(SQL_DATETIME),
92 : TYPE(SQL_SS_VARIANT),
93 : TYPE(SQL_SS_UDT),
94 : TYPE(SQL_SS_XML),
95 : TYPE(SQL_SS_TABLE),
96 : TYPE(SQL_SS_TIME2),
97 : TYPE(SQL_SS_TIMESTAMPOFFSET),
98 : #undef TYPE
99 : { NULL, 0 }
100 : };
101 :
102 : static struct lookup_int sql_bools[] = {
103 : { "SQL_TRUE", SQL_TRUE },
104 : { "SQL_FALSE", SQL_FALSE },
105 : { NULL, 0 }
106 : };
107 :
108 : typedef enum
109 : {
110 : type_INTEGER,
111 : type_SMALLINT,
112 : type_LEN,
113 : type_CHARP
114 : } test_type_t;
115 :
116 : struct attribute
117 : {
118 : const char *name;
119 : int value;
120 : test_type_t type;
121 : const struct lookup_int *lookup;
122 : };
123 :
124 : static const struct attribute attributes[] = {
125 : #define ATTR(s,t) { #s, s, type_##t, NULL }
126 : #define ATTR2(s,t,l) { #s, s, type_##t, l }
127 : ATTR(SQL_COLUMN_LENGTH, INTEGER),
128 : ATTR(SQL_COLUMN_PRECISION, INTEGER),
129 : ATTR(SQL_COLUMN_SCALE, INTEGER),
130 : ATTR(SQL_DESC_LENGTH, LEN),
131 : ATTR(SQL_DESC_OCTET_LENGTH, LEN),
132 : ATTR(SQL_DESC_PRECISION, SMALLINT),
133 : ATTR(SQL_DESC_SCALE, SMALLINT),
134 : ATTR(SQL_DESC_DISPLAY_SIZE, INTEGER),
135 : ATTR(SQL_DESC_TYPE_NAME, CHARP),
136 : ATTR2(SQL_DESC_CONCISE_TYPE, SMALLINT, sql_types),
137 : ATTR2(SQL_DESC_TYPE, SMALLINT, sql_types),
138 : ATTR2(SQL_DESC_UNSIGNED, SMALLINT, sql_bools)
139 : #undef ATTR2
140 : #undef ATTR
141 : };
142 :
143 : static const struct attribute *
144 4904 : lookup_attr(const char *name, odbc_parser *parser)
145 : {
146 : unsigned int i;
147 :
148 4904 : if (!name)
149 0 : odbc_fatal(parser, ": NULL attribute\n");
150 22632 : for (i = 0; i < TDS_VECTOR_SIZE(attributes); ++i)
151 27536 : if (strcmp(attributes[i].name, name) == 0 || strcmp(attributes[i].name + 4, name) == 0)
152 4904 : return &attributes[i];
153 0 : odbc_fatal(parser, ": attribute %s not found\n", name);
154 : return NULL;
155 : }
156 :
157 : #define ATTR_PARAMS \
158 : const struct attribute *attr TDS_UNUSED, \
159 : const char *expected_values[] TDS_UNUSED, \
160 : odbc_parser *parser TDS_UNUSED
161 : typedef void (*check_attr_t) (ATTR_PARAMS);
162 :
163 : static bool
164 : is_contained(const char *s, const char *list[])
165 : {
166 0 : for (;*list; ++list) {
167 106 : if (strcmp(s, *list) == 0)
168 : return true;
169 : }
170 : return false;
171 : }
172 :
173 : static bool
174 : is_contained_lookup(SQLLEN i, const char *list[], const struct lookup_int *table, odbc_parser *parser)
175 : {
176 24 : for (;*list; ++list) {
177 3364 : if (i == lookup(*list, table, parser))
178 : return true;
179 : }
180 : return false;
181 : }
182 :
183 : static void
184 0 : print_values(FILE* f, const char *list[])
185 : {
186 0 : const char *sep = "[";
187 0 : for (;*list; ++list, sep = ", ")
188 0 : fprintf(f, "%s%s", sep, *list);
189 0 : fprintf(f, "]\n");
190 0 : }
191 :
192 : static void
193 3438 : check_attr_ird(ATTR_PARAMS)
194 : {
195 : SQLLEN i;
196 : SQLRETURN ret;
197 :
198 3438 : if (attr->type == type_CHARP) {
199 : char buf[256];
200 : SQLSMALLINT len;
201 :
202 106 : ret = SQLColAttribute(odbc_stmt, 1, attr->value, buf, sizeof(buf), &len, NULL);
203 106 : if (!SQL_SUCCEEDED(ret))
204 0 : odbc_fatal(parser, ": failure not expected\n");
205 106 : buf[sizeof(buf)-1] = 0;
206 159 : if (!is_contained(C((SQLTCHAR*) buf), expected_values)) {
207 0 : g_result = 1;
208 0 : fprintf(stderr, "Line %u: invalid %s got %s expected ", odbc_line_num(parser), attr->name, buf);
209 0 : print_values(stderr, expected_values);
210 : }
211 : return;
212 : }
213 :
214 3332 : i = 0xdeadbeef;
215 3332 : ret = SQLColAttribute(odbc_stmt, 1, attr->value, NULL, SQL_IS_INTEGER, NULL, &i);
216 3332 : if (!SQL_SUCCEEDED(ret))
217 0 : odbc_fatal(parser, ": failure not expected\n");
218 : /* SQL_DESC_LENGTH is the same of SQLDescribeCol len */
219 3332 : if (attr->value == SQL_DESC_LENGTH) {
220 : SQLSMALLINT scale, si;
221 : SQLULEN prec;
222 398 : CHKDescribeCol(1, NULL, 0, NULL, &si, &prec, &scale, &si, "S");
223 398 : if (i != prec)
224 0 : odbc_fatal(parser, ": attr %s SQLDescribeCol len %ld != SQLColAttribute len %ld\n",
225 : attr->name, (long) prec, (long) i);
226 : }
227 3332 : if (attr->value == SQL_DESC_SCALE) {
228 : SQLSMALLINT scale, si;
229 : SQLULEN prec;
230 398 : CHKDescribeCol(1, NULL, 0, NULL, &si, &prec, &scale, &si, "S");
231 398 : if (i != scale)
232 0 : odbc_fatal(parser, ": attr %s SQLDescribeCol scale %ld != SQLColAttribute len %ld\n",
233 : attr->name, (long) scale, (long) i);
234 : }
235 6664 : if (!is_contained_lookup(i, expected_values, attr->lookup, parser)) {
236 0 : g_result = 1;
237 0 : fprintf(stderr, "Line %u: invalid %s got %s expected ", odbc_line_num(parser), attr->name, unlookup(i, attr->lookup));
238 0 : print_values(stderr, expected_values);
239 : }
240 : }
241 :
242 : static void
243 8 : check_attr_ard(ATTR_PARAMS)
244 : {
245 : SQLINTEGER i, ind;
246 : SQLSMALLINT si;
247 : SQLLEN li;
248 : SQLRETURN ret;
249 8 : SQLHDESC desc = SQL_NULL_HDESC;
250 : char buf[256];
251 :
252 : /* get ARD */
253 8 : SQLGetStmtAttr(odbc_stmt, SQL_ATTR_APP_ROW_DESC, &desc, sizeof(desc), &ind);
254 :
255 8 : ret = SQL_ERROR;
256 8 : switch (attr->type) {
257 0 : case type_INTEGER:
258 0 : i = 0xdeadbeef;
259 0 : ret = SQLGetDescField(desc, 1, attr->value, (SQLPOINTER) & i, sizeof(SQLINTEGER), &ind);
260 0 : li = i;
261 0 : break;
262 8 : case type_SMALLINT:
263 8 : si = 0xbeef;
264 8 : ret = SQLGetDescField(desc, 1, attr->value, (SQLPOINTER) & si, sizeof(SQLSMALLINT), &ind);
265 8 : li = si;
266 8 : break;
267 0 : case type_LEN:
268 0 : li = 0xdeadbeef;
269 0 : ret = SQLGetDescField(desc, 1, attr->value, (SQLPOINTER) & li, sizeof(SQLLEN), &ind);
270 0 : break;
271 0 : case type_CHARP:
272 0 : ret = SQLGetDescField(desc, 1, attr->value, buf, sizeof(buf), &ind);
273 0 : if (!SQL_SUCCEEDED(ret))
274 0 : odbc_fatal(parser, ": failure not expected\n");
275 0 : if (!is_contained(C((SQLTCHAR*) buf), expected_values)) {
276 0 : g_result = 1;
277 0 : fprintf(stderr, "Line %u: invalid %s got %s expected ", odbc_line_num(parser), attr->name, buf);
278 0 : print_values(stderr, expected_values);
279 : }
280 0 : return;
281 : }
282 8 : if (!SQL_SUCCEEDED(ret))
283 0 : odbc_fatal(parser, ": failure not expected\n");
284 16 : if (!is_contained_lookup(li, expected_values, attr->lookup, parser)) {
285 0 : g_result = 1;
286 0 : fprintf(stderr, "Line %u: invalid %s got %s expected ", odbc_line_num(parser), attr->name,
287 : unlookup(li, attr->lookup));
288 0 : print_values(stderr, expected_values);
289 : }
290 : }
291 :
292 : /* do not retry any attribute just return expected value so to make caller happy */
293 : static void
294 368 : check_attr_none(ATTR_PARAMS)
295 : {
296 368 : }
297 :
298 : int
299 8 : main(void)
300 : {
301 8 : bool cond = true;
302 : #define TEST_FILE "describecol.in"
303 8 : const char *in_file = FREETDS_SRCDIR "/" TEST_FILE;
304 : FILE *f;
305 : SQLINTEGER i;
306 : SQLLEN len;
307 8 : check_attr_t check_attr_p = check_attr_none;
308 : odbc_parser *parser;
309 :
310 8 : odbc_connect();
311 8 : odbc_command("SET TEXTSIZE 4096");
312 :
313 8 : SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
314 :
315 8 : f = fopen(in_file, "r");
316 8 : if (!f)
317 0 : f = fopen(TEST_FILE, "r");
318 8 : if (!f) {
319 0 : fprintf(stderr, "error opening test file\n");
320 0 : exit(1);
321 : }
322 :
323 : /* cache version */
324 8 : odbc_tds_version();
325 :
326 8 : parser = odbc_init_parser(f);
327 : for (;;) {
328 : char *p;
329 : const char *cmd;
330 :
331 5480 : cmd = odbc_get_cmd_line(parser, &p, &cond);
332 5480 : if (!cmd)
333 : break;
334 :
335 5472 : ODBC_FREE();
336 :
337 5472 : if (strcmp(cmd, "odbc") == 0) {
338 8 : int odbc3 = get_int(odbc_get_tok(&p), parser) == 3 ? 1 : 0;
339 :
340 1174 : if (!cond) continue;
341 :
342 8 : if (odbc_use_version3 != odbc3) {
343 8 : odbc_use_version3 = odbc3;
344 8 : odbc_disconnect();
345 8 : odbc_connect();
346 8 : odbc_command("SET TEXTSIZE 4096");
347 8 : SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
348 : }
349 : }
350 :
351 : /* select type */
352 5472 : if (strcmp(cmd, "select") == 0) {
353 560 : const char *type = odbc_get_str(parser, &p);
354 560 : const char *value = odbc_get_str(parser, &p);
355 : char sql[1024];
356 :
357 716 : if (!cond) continue;
358 :
359 446 : SQLMoreResults(odbc_stmt);
360 446 : odbc_reset_statement();
361 :
362 446 : snprintf(sql, sizeof(sql), "SELECT CONVERT(%s, %s) AS col", type, value);
363 :
364 : /* ignore error, we only need precision of known types */
365 446 : check_attr_p = check_attr_none;
366 446 : if (odbc_command_with_result(odbc_stmt, sql) != SQL_SUCCESS) {
367 42 : odbc_reset_statement();
368 42 : SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
369 42 : continue;
370 : }
371 :
372 404 : CHKFetch("SI");
373 404 : SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
374 404 : check_attr_p = check_attr_ird;
375 : }
376 :
377 : /* set attribute */
378 5316 : if (strcmp(cmd, "set") == 0) {
379 224 : const struct attribute *attr = lookup_attr(odbc_get_tok(&p), parser);
380 224 : const char *value = odbc_get_str(parser, &p);
381 : SQLHDESC desc;
382 : SQLRETURN ret;
383 : SQLINTEGER ind;
384 :
385 224 : if (!value)
386 0 : odbc_fatal(parser, ": value not defined\n");
387 :
388 224 : if (!cond) continue;
389 :
390 : /* get ARD */
391 80 : SQLGetStmtAttr(odbc_stmt, SQL_ATTR_APP_ROW_DESC, &desc, sizeof(desc), &ind);
392 :
393 80 : ret = SQL_ERROR;
394 80 : switch (attr->type) {
395 0 : case type_INTEGER:
396 0 : ret = SQLSetDescField(desc, 1, attr->value, TDS_INT2PTR(lookup(value, attr->lookup, parser)),
397 : sizeof(SQLINTEGER));
398 0 : break;
399 80 : case type_SMALLINT:
400 80 : ret = SQLSetDescField(desc, 1, attr->value, TDS_INT2PTR(lookup(value, attr->lookup, parser)),
401 : sizeof(SQLSMALLINT));
402 80 : break;
403 0 : case type_LEN:
404 0 : ret = SQLSetDescField(desc, 1, attr->value, TDS_INT2PTR(lookup(value, attr->lookup, parser)),
405 : sizeof(SQLLEN));
406 0 : break;
407 0 : case type_CHARP:
408 0 : ret = SQLSetDescField(desc, 1, attr->value, (SQLPOINTER) value, SQL_NTS);
409 0 : break;
410 : }
411 80 : if (!SQL_SUCCEEDED(ret))
412 0 : odbc_fatal(parser, ": failure not expected setting ARD attribute\n");
413 80 : check_attr_p = check_attr_ard;
414 : }
415 :
416 : /* test attribute */
417 5172 : if (strcmp(cmd, "attr") == 0) {
418 4680 : const struct attribute *attr = lookup_attr(odbc_get_tok(&p), parser);
419 : const char *expected[10];
420 : int i;
421 :
422 4680 : expected[0] = odbc_get_str(parser, &p);
423 :
424 4680 : if (!expected[0])
425 0 : odbc_fatal(parser, ": value not defined\n");
426 :
427 4680 : if (!cond) continue;
428 :
429 32 : for (i = 1; ;++i) {
430 3878 : if (i >= 10)
431 0 : odbc_fatal(parser, "Too many values in attribute\n");
432 3846 : p += strspn(p, " \t");
433 3846 : if (!*p) {
434 3814 : expected[i] = NULL;
435 : break;
436 : }
437 32 : expected[i] = odbc_get_str(parser, &p);
438 : }
439 3814 : check_attr_p(attr, expected, parser);
440 : }
441 : }
442 :
443 8 : fclose(f);
444 8 : odbc_free_parser(parser);
445 8 : odbc_disconnect();
446 :
447 8 : printf("Done.\n");
448 8 : return g_result;
449 : }
|