Line data Source code
1 : #include "common.h"
2 : #include <ctype.h>
3 :
4 : /*
5 : * SQLSetStmtAttr
6 : */
7 :
8 : static int g_result = 0;
9 : static unsigned int line_num;
10 :
11 : #ifdef __GNUC__
12 : static void fatal(const char *msg, ...) __attribute__((noreturn));
13 : #endif
14 :
15 : static void
16 0 : fatal(const char *msg, ...)
17 : {
18 : va_list ap;
19 :
20 0 : va_start(ap, msg);
21 0 : vfprintf(stderr, msg, ap);
22 0 : va_end(ap);
23 :
24 0 : exit(1);
25 : }
26 :
27 : static int
28 6 : get_int(const char *s)
29 : {
30 : char *end;
31 : long l;
32 :
33 6 : if (!s)
34 0 : fatal("Line %u: NULL int\n", line_num);
35 6 : l = strtol(s, &end, 0);
36 6 : if (end[0])
37 0 : fatal("Line %u: Invalid int\n", line_num);
38 6 : return (int) l;
39 : }
40 :
41 : struct lookup_int
42 : {
43 : const char *name;
44 : int value;
45 : };
46 :
47 : static int
48 54 : lookup(const char *name, const struct lookup_int *table)
49 : {
50 54 : if (!table)
51 0 : return get_int(name);
52 :
53 42 : for (; table->name; ++table)
54 96 : if (strcmp(table->name, name) == 0)
55 54 : return table->value;
56 :
57 0 : return get_int(name);
58 : }
59 :
60 : static const char *
61 : unlookup(int value, const struct lookup_int *table)
62 : {
63 0 : if (!table)
64 : return "??";
65 :
66 0 : for (; table->name; ++table)
67 0 : if (table->value == value)
68 : return table->name;
69 :
70 : return "??";
71 : }
72 :
73 : static struct lookup_int concurrency[] = {
74 : #define TYPE(s) { #s, s }
75 : TYPE(SQL_CONCUR_READ_ONLY),
76 : TYPE(SQL_CONCUR_LOCK),
77 : TYPE(SQL_CONCUR_ROWVER),
78 : TYPE(SQL_CONCUR_VALUES),
79 : #undef TYPE
80 : { NULL, 0 }
81 : };
82 :
83 : static struct lookup_int scrollable[] = {
84 : #define TYPE(s) { #s, s }
85 : TYPE(SQL_NONSCROLLABLE),
86 : TYPE(SQL_SCROLLABLE),
87 : #undef TYPE
88 : { NULL, 0 }
89 : };
90 :
91 : static struct lookup_int sensitivity[] = {
92 : #define TYPE(s) { #s, s }
93 : TYPE(SQL_UNSPECIFIED),
94 : TYPE(SQL_INSENSITIVE),
95 : TYPE(SQL_SENSITIVE),
96 : #undef TYPE
97 : { NULL, 0 }
98 : };
99 :
100 : static struct lookup_int cursor_type[] = {
101 : #define TYPE(s) { #s, s }
102 : TYPE(SQL_CURSOR_FORWARD_ONLY),
103 : TYPE(SQL_CURSOR_STATIC),
104 : TYPE(SQL_CURSOR_KEYSET_DRIVEN),
105 : TYPE(SQL_CURSOR_DYNAMIC),
106 : #undef TYPE
107 : { NULL, 0 }
108 : };
109 :
110 : static struct lookup_int noscan[] = {
111 : #define TYPE(s) { #s, s }
112 : TYPE(SQL_NOSCAN_OFF),
113 : TYPE(SQL_NOSCAN_ON),
114 : #undef TYPE
115 : { NULL, 0 }
116 : };
117 :
118 : static struct lookup_int retrieve_data[] = {
119 : #define TYPE(s) { #s, s }
120 : TYPE(SQL_RD_ON),
121 : TYPE(SQL_RD_OFF),
122 : #undef TYPE
123 : { NULL, 0 }
124 : };
125 :
126 : static struct lookup_int simulate_cursor[] = {
127 : #define TYPE(s) { #s, s }
128 : TYPE(SQL_SC_NON_UNIQUE),
129 : TYPE(SQL_SC_TRY_UNIQUE),
130 : TYPE(SQL_SC_UNIQUE),
131 : #undef TYPE
132 : { NULL, 0 }
133 : };
134 :
135 : static struct lookup_int use_bookmarks[] = {
136 : #define TYPE(s) { #s, s }
137 : TYPE(SQL_UB_OFF),
138 : TYPE(SQL_UB_VARIABLE),
139 : TYPE(SQL_UB_FIXED),
140 : #undef TYPE
141 : { NULL, 0 }
142 : };
143 :
144 : typedef enum
145 : {
146 : type_INTEGER,
147 : type_UINTEGER,
148 : type_SMALLINT,
149 : type_LEN,
150 : type_CHARP,
151 : type_DESC,
152 : type_VOIDP
153 : } test_type_t;
154 :
155 : struct attribute
156 : {
157 : const char *name;
158 : int value;
159 : test_type_t type;
160 : const struct lookup_int *lookup;
161 : };
162 :
163 : static const struct attribute attributes[] = {
164 : #define ATTR(s,t) { #s, s, type_##t, NULL }
165 : #define ATTR2(s,t,l) { #s, s, type_##t, l }
166 : ATTR(SQL_ATTR_APP_PARAM_DESC, DESC),
167 : ATTR(SQL_ATTR_APP_ROW_DESC, DESC),
168 : ATTR(SQL_ATTR_ASYNC_ENABLE, UINTEGER),
169 : ATTR2(SQL_ATTR_CONCURRENCY, UINTEGER, concurrency),
170 : ATTR2(SQL_ATTR_CURSOR_SCROLLABLE, UINTEGER, scrollable),
171 : ATTR2(SQL_ATTR_CURSOR_SENSITIVITY, UINTEGER, sensitivity),
172 : ATTR2(SQL_ATTR_CURSOR_TYPE, UINTEGER, cursor_type),
173 : ATTR(SQL_ATTR_ENABLE_AUTO_IPD, UINTEGER),
174 : ATTR(SQL_ATTR_FETCH_BOOKMARK_PTR, VOIDP),
175 : ATTR(SQL_ATTR_IMP_PARAM_DESC, DESC),
176 : ATTR(SQL_ATTR_IMP_ROW_DESC, DESC),
177 : ATTR(SQL_ATTR_KEYSET_SIZE, UINTEGER),
178 : ATTR(SQL_ATTR_MAX_LENGTH, UINTEGER),
179 : ATTR(SQL_ATTR_MAX_ROWS, UINTEGER),
180 : ATTR(SQL_ATTR_METADATA_ID, UINTEGER),
181 : ATTR2(SQL_ATTR_NOSCAN, UINTEGER, noscan),
182 : ATTR(SQL_ATTR_PARAM_BIND_OFFSET_PTR, VOIDP),
183 : ATTR(SQL_ATTR_PARAM_BIND_OFFSET_PTR, VOIDP),
184 : ATTR(SQL_ATTR_PARAM_BIND_TYPE, UINTEGER),
185 : ATTR(SQL_ATTR_PARAM_OPERATION_PTR, VOIDP),
186 : ATTR(SQL_ATTR_PARAM_STATUS_PTR, VOIDP),
187 : ATTR(SQL_ATTR_PARAMS_PROCESSED_PTR, VOIDP),
188 : ATTR(SQL_ATTR_PARAMSET_SIZE, UINTEGER),
189 : ATTR(SQL_ATTR_QUERY_TIMEOUT, UINTEGER),
190 : ATTR2(SQL_ATTR_RETRIEVE_DATA, UINTEGER, retrieve_data),
191 : ATTR(SQL_ATTR_ROW_ARRAY_SIZE, UINTEGER),
192 : ATTR(SQL_ATTR_ROW_BIND_OFFSET_PTR, VOIDP),
193 : ATTR(SQL_ATTR_ROW_BIND_TYPE, UINTEGER),
194 : ATTR(SQL_ATTR_ROW_NUMBER, UINTEGER),
195 : ATTR(SQL_ATTR_ROW_OPERATION_PTR, VOIDP),
196 : ATTR(SQL_ATTR_ROW_STATUS_PTR, VOIDP),
197 : ATTR(SQL_ATTR_ROWS_FETCHED_PTR, VOIDP),
198 : ATTR2(SQL_ATTR_SIMULATE_CURSOR, UINTEGER, simulate_cursor),
199 : ATTR2(SQL_ATTR_USE_BOOKMARKS, UINTEGER, use_bookmarks),
200 : #undef ATTR2
201 : #undef ATTR
202 : };
203 :
204 : static const struct attribute *
205 54 : lookup_attr(const char *name)
206 : {
207 : unsigned int i;
208 :
209 54 : if (!name)
210 0 : fatal("Line %u: NULL attribute\n", line_num);
211 246 : for (i = 0; i < TDS_VECTOR_SIZE(attributes); ++i)
212 300 : if (strcmp(attributes[i].name, name) == 0 || strcmp(attributes[i].name + 4, name) == 0)
213 54 : return &attributes[i];
214 0 : fatal("Line %u: attribute %s not found\n", line_num, name);
215 : return NULL;
216 : }
217 :
218 : #define SEP " \t\n"
219 :
220 : #define ATTR_PARAMS \
221 : const struct attribute *attr TDS_UNUSED, \
222 : int expected TDS_UNUSED
223 : typedef int (*get_attr_t) (ATTR_PARAMS);
224 :
225 : static int
226 48 : get_attr_stmt(ATTR_PARAMS)
227 : {
228 : SQLINTEGER i, ind;
229 : SQLSMALLINT si;
230 : SQLLEN li;
231 : SQLRETURN ret;
232 :
233 48 : ret = SQL_ERROR;
234 48 : switch (attr->type) {
235 48 : case type_INTEGER:
236 : case type_UINTEGER:
237 48 : i = 0xdeadbeef;
238 48 : ret = SQLGetStmtAttr(odbc_stmt, attr->value, (SQLPOINTER) & i, sizeof(SQLINTEGER), &ind);
239 48 : break;
240 0 : case type_SMALLINT:
241 0 : si = 0xbeef;
242 0 : ret = SQLGetStmtAttr(odbc_stmt, attr->value, (SQLPOINTER) & si, sizeof(SQLSMALLINT), &ind);
243 0 : i = si;
244 0 : break;
245 0 : case type_LEN:
246 0 : li = 0xdeadbeef;
247 0 : ret = SQLGetStmtAttr(odbc_stmt, attr->value, (SQLPOINTER) & li, sizeof(SQLLEN), &ind);
248 0 : i = li;
249 0 : break;
250 0 : case type_VOIDP:
251 : case type_DESC:
252 : case type_CHARP:
253 0 : fatal("Line %u: CHAR* check still not supported\n", line_num);
254 : break;
255 : }
256 48 : if (!SQL_SUCCEEDED(ret))
257 0 : fatal("Line %u: failure not expected\n", line_num);
258 48 : return i;
259 : }
260 :
261 : #if 0
262 : /* do not retry any attribute just return expected value so to make caller happy */
263 : static int
264 : get_attr_none(ATTR_PARAMS)
265 : {
266 : return expected;
267 : }
268 : #endif
269 :
270 : int
271 8 : main(void)
272 : {
273 : #define TEST_FILE "attributes.in"
274 8 : const char *in_file = FREETDS_SRCDIR "/" TEST_FILE;
275 : FILE *f;
276 : char buf[256];
277 : SQLINTEGER i;
278 : SQLLEN len;
279 8 : get_attr_t get_attr_p = get_attr_stmt;
280 :
281 8 : odbc_connect();
282 : /* TODO find another way */
283 8 : odbc_check_cursor();
284 6 : odbc_command("SET TEXTSIZE 4096");
285 :
286 6 : SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
287 :
288 6 : f = fopen(in_file, "r");
289 6 : if (!f)
290 0 : f = fopen(TEST_FILE, "r");
291 6 : if (!f) {
292 0 : fprintf(stderr, "error opening test file\n");
293 0 : exit(1);
294 : }
295 :
296 6 : line_num = 0;
297 102 : while (fgets(buf, sizeof(buf), f)) {
298 90 : char *p = buf, *cmd;
299 :
300 90 : ++line_num;
301 :
302 198 : while (isspace((unsigned char) *p))
303 18 : ++p;
304 90 : cmd = strtok(p, SEP);
305 :
306 : /* skip comments */
307 90 : if (!cmd || cmd[0] == '#' || cmd[0] == 0 || cmd[0] == '\n')
308 24 : continue;
309 :
310 66 : if (strcmp(cmd, "odbc") == 0) {
311 6 : int odbc3 = get_int(strtok(NULL, SEP)) == 3 ? 1 : 0;
312 :
313 6 : if (odbc_use_version3 != odbc3) {
314 6 : odbc_use_version3 = odbc3;
315 6 : odbc_disconnect();
316 6 : odbc_connect();
317 6 : odbc_command("SET TEXTSIZE 4096");
318 6 : SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
319 : }
320 6 : continue;
321 : }
322 :
323 : /* set attribute */
324 60 : if (strcmp(cmd, "set") == 0) {
325 6 : const struct attribute *attr = lookup_attr(strtok(NULL, SEP));
326 6 : char *value = strtok(NULL, SEP);
327 : SQLRETURN ret;
328 :
329 6 : if (!value)
330 0 : fatal("Line %u: value not defined\n", line_num);
331 :
332 6 : ret = SQL_ERROR;
333 6 : switch (attr->type) {
334 6 : case type_UINTEGER:
335 : case type_INTEGER:
336 6 : ret = SQLSetStmtAttr(odbc_stmt, attr->value, TDS_INT2PTR(lookup(value, attr->lookup)),
337 : sizeof(SQLINTEGER));
338 6 : break;
339 0 : case type_SMALLINT:
340 0 : ret = SQLSetStmtAttr(odbc_stmt, attr->value, TDS_INT2PTR(lookup(value, attr->lookup)),
341 : sizeof(SQLSMALLINT));
342 0 : break;
343 0 : case type_LEN:
344 0 : ret = SQLSetStmtAttr(odbc_stmt, attr->value, TDS_INT2PTR(lookup(value, attr->lookup)),
345 : sizeof(SQLLEN));
346 0 : break;
347 0 : case type_CHARP:
348 0 : ret = SQLSetStmtAttr(odbc_stmt, attr->value, (SQLPOINTER) value, SQL_NTS);
349 0 : break;
350 0 : case type_VOIDP:
351 : case type_DESC:
352 0 : fatal("Line %u: not implemented\n");
353 : }
354 6 : if (!SQL_SUCCEEDED(ret))
355 0 : fatal("Line %u: failure not expected setting statement attribute\n", line_num);
356 6 : get_attr_p = get_attr_stmt;
357 6 : continue;
358 : }
359 :
360 : /* test attribute */
361 54 : if (strcmp(cmd, "attr") == 0) {
362 48 : const struct attribute *attr = lookup_attr(strtok(NULL, SEP));
363 48 : char *value = strtok(NULL, SEP);
364 48 : int i, expected = lookup(value, attr->lookup);
365 :
366 48 : if (!value)
367 0 : fatal("Line %u: value not defined\n", line_num);
368 :
369 48 : i = get_attr_p(attr, expected);
370 48 : if (i != expected) {
371 0 : g_result = 1;
372 0 : fprintf(stderr, "Line %u: invalid %s got %d(%s) expected %s\n", line_num, attr->name, i, unlookup(i, attr->lookup), value);
373 : }
374 48 : continue;
375 : }
376 :
377 6 : if (strcmp(cmd, "reset") == 0) {
378 6 : odbc_reset_statement();
379 6 : continue;
380 : }
381 :
382 0 : fatal("Line %u: command '%s' not handled\n", line_num, cmd);
383 : }
384 :
385 6 : fclose(f);
386 6 : odbc_disconnect();
387 :
388 6 : printf("Done.\n");
389 6 : return g_result;
390 : }
|