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