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