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)
16 : {
17 : char *end;
18 : long l;
19 :
20 3188 : if (!s)
21 0 : odbc_fatal(": NULL int\n");
22 3188 : l = strtol(s, &end, 0);
23 3188 : if (end[0])
24 0 : odbc_fatal(": 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)
36 : {
37 3444 : if (!table)
38 3180 : return get_int(name);
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);
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)
145 : {
146 : unsigned int i;
147 :
148 4904 : if (!name)
149 0 : odbc_fatal(": 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(": 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 : typedef void (*check_attr_t) (ATTR_PARAMS);
161 :
162 : static bool
163 : is_contained(const char *s, const char *list[])
164 : {
165 0 : for (;*list; ++list) {
166 106 : if (strcmp(s, *list) == 0)
167 : return true;
168 : }
169 : return false;
170 : }
171 :
172 : static bool
173 : is_contained_lookup(SQLLEN i, const char *list[], const struct lookup_int *table)
174 : {
175 24 : for (;*list; ++list) {
176 3364 : if (i == lookup(*list, table))
177 : return true;
178 : }
179 : return false;
180 : }
181 :
182 : static void
183 0 : print_values(FILE* f, const char *list[])
184 : {
185 0 : const char *sep = "[";
186 0 : for (;*list; ++list, sep = ", ")
187 0 : fprintf(f, "%s%s", sep, *list);
188 0 : fprintf(f, "]\n");
189 0 : }
190 :
191 : static void
192 3438 : check_attr_ird(ATTR_PARAMS)
193 : {
194 : SQLLEN i;
195 : SQLRETURN ret;
196 :
197 3438 : if (attr->type == type_CHARP) {
198 : char buf[256];
199 : SQLSMALLINT len;
200 :
201 106 : ret = SQLColAttribute(odbc_stmt, 1, attr->value, buf, sizeof(buf), &len, NULL);
202 106 : if (!SQL_SUCCEEDED(ret))
203 0 : odbc_fatal(": failure not expected\n");
204 106 : buf[sizeof(buf)-1] = 0;
205 159 : if (!is_contained(C((SQLTCHAR*) buf), expected_values)) {
206 0 : g_result = 1;
207 0 : fprintf(stderr, "Line %u: invalid %s got %s expected ", odbc_line_num, attr->name, buf);
208 0 : print_values(stderr, expected_values);
209 : }
210 : return;
211 : }
212 :
213 3332 : i = 0xdeadbeef;
214 3332 : ret = SQLColAttribute(odbc_stmt, 1, attr->value, NULL, SQL_IS_INTEGER, NULL, &i);
215 3332 : if (!SQL_SUCCEEDED(ret))
216 0 : odbc_fatal(": failure not expected\n");
217 : /* SQL_DESC_LENGTH is the same of SQLDescribeCol len */
218 3332 : if (attr->value == SQL_DESC_LENGTH) {
219 : SQLSMALLINT scale, si;
220 : SQLULEN prec;
221 398 : CHKDescribeCol(1, NULL, 0, NULL, &si, &prec, &scale, &si, "S");
222 398 : if (i != prec)
223 0 : odbc_fatal(": attr %s SQLDescribeCol len %ld != SQLColAttribute len %ld\n", attr->name, (long) prec, (long) i);
224 : }
225 3332 : if (attr->value == SQL_DESC_SCALE) {
226 : SQLSMALLINT scale, si;
227 : SQLULEN prec;
228 398 : CHKDescribeCol(1, NULL, 0, NULL, &si, &prec, &scale, &si, "S");
229 398 : if (i != scale)
230 0 : odbc_fatal(": attr %s SQLDescribeCol scale %ld != SQLColAttribute len %ld\n", attr->name, (long) scale, (long) i);
231 : }
232 6664 : if (!is_contained_lookup(i, expected_values, attr->lookup)) {
233 0 : g_result = 1;
234 0 : fprintf(stderr, "Line %u: invalid %s got %s expected ", odbc_line_num, attr->name, unlookup(i, attr->lookup));
235 0 : print_values(stderr, expected_values);
236 : }
237 : }
238 :
239 : static void
240 8 : check_attr_ard(ATTR_PARAMS)
241 : {
242 : SQLINTEGER i, ind;
243 : SQLSMALLINT si;
244 : SQLLEN li;
245 : SQLRETURN ret;
246 8 : SQLHDESC desc = SQL_NULL_HDESC;
247 : char buf[256];
248 :
249 : /* get ARD */
250 8 : SQLGetStmtAttr(odbc_stmt, SQL_ATTR_APP_ROW_DESC, &desc, sizeof(desc), &ind);
251 :
252 8 : ret = SQL_ERROR;
253 8 : switch (attr->type) {
254 0 : case type_INTEGER:
255 0 : i = 0xdeadbeef;
256 0 : ret = SQLGetDescField(desc, 1, attr->value, (SQLPOINTER) & i, sizeof(SQLINTEGER), &ind);
257 0 : li = i;
258 0 : break;
259 8 : case type_SMALLINT:
260 8 : si = 0xbeef;
261 8 : ret = SQLGetDescField(desc, 1, attr->value, (SQLPOINTER) & si, sizeof(SQLSMALLINT), &ind);
262 8 : li = si;
263 8 : break;
264 0 : case type_LEN:
265 0 : li = 0xdeadbeef;
266 0 : ret = SQLGetDescField(desc, 1, attr->value, (SQLPOINTER) & li, sizeof(SQLLEN), &ind);
267 0 : break;
268 0 : case type_CHARP:
269 0 : ret = SQLGetDescField(desc, 1, attr->value, buf, sizeof(buf), &ind);
270 0 : if (!SQL_SUCCEEDED(ret))
271 0 : odbc_fatal(": failure not expected\n");
272 0 : if (!is_contained(C((SQLTCHAR*) buf), expected_values)) {
273 0 : g_result = 1;
274 0 : fprintf(stderr, "Line %u: invalid %s got %s expected ", odbc_line_num, attr->name, buf);
275 0 : print_values(stderr, expected_values);
276 : }
277 0 : return;
278 : }
279 8 : if (!SQL_SUCCEEDED(ret))
280 0 : odbc_fatal(": failure not expected\n");
281 16 : if (!is_contained_lookup(li, expected_values, attr->lookup)) {
282 0 : g_result = 1;
283 0 : fprintf(stderr, "Line %u: invalid %s got %s expected ", odbc_line_num, attr->name, unlookup(li, attr->lookup));
284 0 : print_values(stderr, expected_values);
285 : }
286 : }
287 :
288 : /* do not retry any attribute just return expected value so to make caller happy */
289 : static void
290 368 : check_attr_none(ATTR_PARAMS)
291 : {
292 368 : }
293 :
294 : int
295 8 : main(void)
296 : {
297 8 : int cond = 1;
298 : #define TEST_FILE "describecol.in"
299 8 : const char *in_file = FREETDS_SRCDIR "/" TEST_FILE;
300 : FILE *f;
301 : SQLINTEGER i;
302 : SQLLEN len;
303 8 : check_attr_t check_attr_p = check_attr_none;
304 :
305 8 : odbc_connect();
306 8 : odbc_init_bools();
307 8 : odbc_command("SET TEXTSIZE 4096");
308 :
309 8 : SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
310 :
311 8 : f = fopen(in_file, "r");
312 8 : if (!f)
313 0 : f = fopen(TEST_FILE, "r");
314 8 : if (!f) {
315 0 : fprintf(stderr, "error opening test file\n");
316 0 : exit(1);
317 : }
318 :
319 8 : odbc_init_parser(f);
320 : for (;;) {
321 : char *p;
322 : const char *cmd;
323 :
324 5480 : cmd = odbc_get_cmd_line(&p, &cond);
325 5480 : if (!cmd)
326 : break;
327 :
328 5472 : ODBC_FREE();
329 :
330 5472 : if (strcmp(cmd, "odbc") == 0) {
331 8 : int odbc3 = get_int(odbc_get_tok(&p)) == 3 ? 1 : 0;
332 :
333 1174 : if (!cond) continue;
334 :
335 8 : if (odbc_use_version3 != odbc3) {
336 8 : odbc_use_version3 = odbc3;
337 8 : odbc_disconnect();
338 8 : odbc_connect();
339 8 : odbc_command("SET TEXTSIZE 4096");
340 8 : SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
341 : }
342 : }
343 :
344 : /* select type */
345 5472 : if (strcmp(cmd, "select") == 0) {
346 560 : const char *type = odbc_get_str(&p);
347 560 : const char *value = odbc_get_str(&p);
348 : char sql[1024];
349 :
350 716 : if (!cond) continue;
351 :
352 446 : SQLMoreResults(odbc_stmt);
353 446 : odbc_reset_statement();
354 :
355 446 : snprintf(sql, sizeof(sql), "SELECT CONVERT(%s, %s) AS col", type, value);
356 :
357 : /* ignore error, we only need precision of known types */
358 446 : check_attr_p = check_attr_none;
359 446 : if (odbc_command_with_result(odbc_stmt, sql) != SQL_SUCCESS) {
360 42 : odbc_reset_statement();
361 42 : SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
362 42 : continue;
363 : }
364 :
365 404 : CHKFetch("SI");
366 404 : SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
367 404 : check_attr_p = check_attr_ird;
368 : }
369 :
370 : /* set attribute */
371 5316 : if (strcmp(cmd, "set") == 0) {
372 224 : const struct attribute *attr = lookup_attr(odbc_get_tok(&p));
373 224 : const char *value = odbc_get_str(&p);
374 : SQLHDESC desc;
375 : SQLRETURN ret;
376 : SQLINTEGER ind;
377 :
378 224 : if (!value)
379 0 : odbc_fatal(": value not defined\n");
380 :
381 224 : if (!cond) continue;
382 :
383 : /* get ARD */
384 80 : SQLGetStmtAttr(odbc_stmt, SQL_ATTR_APP_ROW_DESC, &desc, sizeof(desc), &ind);
385 :
386 80 : ret = SQL_ERROR;
387 80 : switch (attr->type) {
388 0 : case type_INTEGER:
389 0 : ret = SQLSetDescField(desc, 1, attr->value, TDS_INT2PTR(lookup(value, attr->lookup)),
390 : sizeof(SQLINTEGER));
391 0 : break;
392 80 : case type_SMALLINT:
393 80 : ret = SQLSetDescField(desc, 1, attr->value, TDS_INT2PTR(lookup(value, attr->lookup)),
394 : sizeof(SQLSMALLINT));
395 80 : break;
396 0 : case type_LEN:
397 0 : ret = SQLSetDescField(desc, 1, attr->value, TDS_INT2PTR(lookup(value, attr->lookup)),
398 : sizeof(SQLLEN));
399 0 : break;
400 0 : case type_CHARP:
401 0 : ret = SQLSetDescField(desc, 1, attr->value, (SQLPOINTER) value, SQL_NTS);
402 0 : break;
403 : }
404 80 : if (!SQL_SUCCEEDED(ret))
405 0 : odbc_fatal(": failure not expected setting ARD attribute\n");
406 80 : check_attr_p = check_attr_ard;
407 : }
408 :
409 : /* test attribute */
410 5172 : if (strcmp(cmd, "attr") == 0) {
411 4680 : const struct attribute *attr = lookup_attr(odbc_get_tok(&p));
412 : const char *expected[10];
413 : int i;
414 :
415 4680 : expected[0] = odbc_get_str(&p);
416 :
417 4680 : if (!expected[0])
418 0 : odbc_fatal(": value not defined\n");
419 :
420 4680 : if (!cond) continue;
421 :
422 32 : for (i = 1; ;++i) {
423 3878 : if (i >= 10)
424 0 : odbc_fatal("Too many values in attribute\n");
425 3846 : p += strspn(p, " \t");
426 3846 : if (!*p) {
427 3814 : expected[i] = NULL;
428 : break;
429 : }
430 32 : expected[i] = odbc_get_str(&p);
431 : }
432 3814 : check_attr_p(attr, expected);
433 : }
434 : }
435 :
436 8 : fclose(f);
437 8 : odbc_clear_bools();
438 8 : odbc_disconnect();
439 :
440 8 : printf("Done.\n");
441 8 : return g_result;
442 : }
|