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