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