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(long int value, const struct odbc_lookup_int *table)
42 : {
43 : static char buf[32];
44 :
45 0 : sprintf(buf, "%ld", 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 : int
249 10 : main(void)
250 : {
251 10 : bool cond = true;
252 : #define TEST_FILE "describecol.in"
253 10 : const char *in_file = FREETDS_SRCDIR "/" TEST_FILE;
254 : FILE *f;
255 : SQLINTEGER i;
256 : SQLLEN len;
257 10 : check_attr_t check_attr_p = check_attr_none;
258 : odbc_parser *parser;
259 :
260 10 : odbc_connect();
261 10 : odbc_command("SET TEXTSIZE 4096");
262 :
263 10 : SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
264 :
265 10 : f = fopen(in_file, "r");
266 10 : if (!f)
267 0 : f = fopen(TEST_FILE, "r");
268 10 : if (!f) {
269 0 : fprintf(stderr, "error opening test file\n");
270 0 : exit(1);
271 : }
272 :
273 : /* cache version */
274 10 : odbc_tds_version();
275 :
276 10 : parser = odbc_init_parser(f);
277 : for (;;) {
278 : char *p;
279 : const char *cmd;
280 :
281 6850 : cmd = odbc_get_cmd_line(parser, &p, &cond);
282 6850 : if (!cmd)
283 : break;
284 :
285 6840 : ODBC_FREE();
286 :
287 6840 : if (strcmp(cmd, "odbc") == 0) {
288 10 : int odbc3 = get_int(odbc_get_tok(&p), parser) == 3 ? 1 : 0;
289 :
290 1312 : if (!cond) continue;
291 :
292 10 : if (odbc_use_version3 != odbc3) {
293 10 : odbc_use_version3 = odbc3;
294 10 : odbc_disconnect();
295 10 : odbc_connect();
296 10 : odbc_command("SET TEXTSIZE 4096");
297 10 : SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
298 : }
299 : }
300 :
301 : /* select type */
302 6840 : if (strcmp(cmd, "select") == 0) {
303 700 : const char *type = odbc_get_str(parser, &p);
304 700 : const char *value = odbc_get_str(parser, &p);
305 : char sql[1024];
306 :
307 876 : if (!cond) continue;
308 :
309 574 : SQLMoreResults(odbc_stmt);
310 574 : odbc_reset_statement();
311 :
312 574 : snprintf(sql, sizeof(sql), "SELECT CONVERT(%s, %s) AS col", type, value);
313 :
314 : /* ignore error, we only need precision of known types */
315 574 : check_attr_p = check_attr_none;
316 574 : if (odbc_command_with_result(odbc_stmt, sql) != SQL_SUCCESS) {
317 50 : odbc_reset_statement();
318 50 : SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
319 50 : continue;
320 : }
321 :
322 524 : CHKFetch("SI");
323 524 : SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
324 524 : check_attr_p = check_attr_ird;
325 : }
326 :
327 : /* set attribute */
328 6664 : if (strcmp(cmd, "set") == 0) {
329 280 : const struct attribute *attr = lookup_attr(odbc_get_tok(&p), parser);
330 280 : const char *value = odbc_get_str(parser, &p);
331 : SQLHDESC desc;
332 : SQLRETURN ret;
333 : SQLINTEGER ind;
334 :
335 280 : if (!value)
336 0 : odbc_fatal(parser, ": value not defined\n");
337 :
338 280 : if (!cond) continue;
339 :
340 : /* get ARD */
341 120 : SQLGetStmtAttr(odbc_stmt, SQL_ATTR_APP_ROW_DESC, &desc, sizeof(desc), &ind);
342 :
343 120 : ret = SQL_ERROR;
344 120 : switch (attr->type) {
345 0 : case type_INTEGER:
346 0 : ret = SQLSetDescField(desc, 1, attr->value, TDS_INT2PTR(lookup(value, attr->lookup, parser)),
347 : sizeof(SQLINTEGER));
348 0 : break;
349 120 : case type_SMALLINT:
350 120 : ret = SQLSetDescField(desc, 1, attr->value, TDS_INT2PTR(lookup(value, attr->lookup, parser)),
351 : sizeof(SQLSMALLINT));
352 120 : break;
353 0 : case type_LEN:
354 0 : ret = SQLSetDescField(desc, 1, attr->value, TDS_INT2PTR(lookup(value, attr->lookup, parser)),
355 : sizeof(SQLLEN));
356 0 : break;
357 0 : case type_CHARP:
358 0 : ret = SQLSetDescField(desc, 1, attr->value, (SQLPOINTER) value, SQL_NTS);
359 0 : break;
360 : }
361 120 : if (!SQL_SUCCEEDED(ret))
362 0 : odbc_fatal(parser, ": failure not expected setting ARD attribute\n");
363 120 : check_attr_p = check_attr_ard;
364 : }
365 :
366 : /* test attribute */
367 6504 : if (strcmp(cmd, "attr") == 0) {
368 5850 : const struct attribute *attr = lookup_attr(odbc_get_tok(&p), parser);
369 : const char *expected[10];
370 : int i;
371 :
372 5850 : expected[0] = odbc_get_str(parser, &p);
373 :
374 5850 : if (!expected[0])
375 0 : odbc_fatal(parser, ": value not defined\n");
376 :
377 5850 : if (!cond) continue;
378 :
379 40 : for (i = 1; ;++i) {
380 4964 : if (i >= 10)
381 0 : odbc_fatal(parser, "Too many values in attribute\n");
382 4924 : p += strspn(p, " \t");
383 4924 : if (!*p) {
384 4884 : expected[i] = NULL;
385 : break;
386 : }
387 40 : expected[i] = odbc_get_str(parser, &p);
388 : }
389 4884 : check_attr_p(attr, expected, parser);
390 : }
391 : }
392 :
393 10 : fclose(f);
394 10 : odbc_free_parser(parser);
395 10 : odbc_disconnect();
396 :
397 10 : printf("Done.\n");
398 10 : return g_result;
399 : }
|