1 #include "common.h"
2
3 SQLHENV env;
4 SQLHDBC conn;
5
6 void
print_diag(char * msg,SQLSMALLINT htype,SQLHANDLE handle)7 print_diag(char *msg, SQLSMALLINT htype, SQLHANDLE handle)
8 {
9 char sqlstate[32];
10 char message[1000];
11 SQLINTEGER nativeerror;
12 SQLSMALLINT textlen;
13 SQLRETURN ret;
14 SQLSMALLINT recno = 0;
15
16 if (msg)
17 printf("%s\n", msg);
18
19 do
20 {
21 recno++;
22 ret = SQLGetDiagRec(htype, handle, recno, sqlstate, &nativeerror,
23 message, sizeof(message), &textlen);
24 if (ret == SQL_INVALID_HANDLE)
25 printf("Invalid handle\n");
26 else if (SQL_SUCCEEDED(ret))
27 printf("%s=%s\n", sqlstate, message);
28 } while (ret == SQL_SUCCESS);
29
30 if (ret == SQL_NO_DATA && recno == 1)
31 printf("No error information\n");
32 }
33
34 const char * const default_dsn = "psqlodbc_test_dsn";
35 const char * const test_dsn_env = "PSQLODBC_TEST_DSN";
36 const char * const test_dsn_ansi = "psqlodbc_test_dsn_ansi";
37
get_test_dsn(void)38 const char *get_test_dsn(void)
39 {
40 char *env = getenv(test_dsn_env);
41
42 if (NULL != env && env[0])
43 return env;
44 return default_dsn;
45 }
46
IsAnsi(void)47 int IsAnsi(void)
48 {
49 return (NULL != strstr(get_test_dsn(), "_ansi"));
50 }
51
52 void
test_connect_ext(char * extraparams)53 test_connect_ext(char *extraparams)
54 {
55 SQLRETURN ret;
56 SQLCHAR str[1024];
57 SQLSMALLINT strl;
58 SQLCHAR dsn[1024];
59 const char * const test_dsn = get_test_dsn();
60 char *envvar;
61
62 /*
63 * Use an environment variable to switch settings of connection
64 * strings throughout the regression test. Note that extraparams
65 * parameters have precedence over the environment variable.
66 * ODBC spec says
67 * If any keywords are repeated in the connection string,
68 * the driver uses the value associated with the first
69 * occurrence of the keyword.
70 * But the current psqlodbc driver uses the value associated with
71 * the last occurrence of the keyword. Here we place extraparams
72 * both before and after the value of the environment variable
73 * so as to protect the priority order whichever way we take.
74 */
75 if ((envvar = getenv("COMMON_CONNECTION_STRING_FOR_REGRESSION_TEST")) != NULL && envvar[0] != '\0')
76 {
77 if (NULL == extraparams)
78 snprintf(dsn, sizeof(dsn), "DSN=%s;%s", test_dsn, envvar);
79 else
80 snprintf(dsn, sizeof(dsn), "DSN=%s;%s;%s;%s",
81 test_dsn, extraparams, envvar, extraparams);
82 }
83 else
84 snprintf(dsn, sizeof(dsn), "DSN=%s;%s",
85 test_dsn, extraparams ? extraparams : "");
86
87 SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
88
89 SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
90
91 SQLAllocHandle(SQL_HANDLE_DBC, env, &conn);
92 ret = SQLDriverConnect(conn, NULL, dsn, SQL_NTS,
93 str, sizeof(str), &strl,
94 SQL_DRIVER_COMPLETE);
95 if (SQL_SUCCEEDED(ret)) {
96 printf("connected\n");
97 } else {
98 print_diag("SQLDriverConnect failed.", SQL_HANDLE_DBC, conn);
99 fflush(stdout);
100 exit(1);
101 }
102 }
103
104 void
test_connect(void)105 test_connect(void)
106 {
107 test_connect_ext(NULL);
108 }
109
110 void
test_disconnect(void)111 test_disconnect(void)
112 {
113 SQLRETURN rc;
114
115 printf("disconnecting\n");
116 rc = SQLDisconnect(conn);
117 if (!SQL_SUCCEEDED(rc))
118 {
119 print_diag("SQLDisconnect failed", SQL_HANDLE_DBC, conn);
120 fflush(stdout);
121 exit(1);
122 }
123
124 rc = SQLFreeHandle(SQL_HANDLE_DBC, conn);
125 if (!SQL_SUCCEEDED(rc))
126 {
127 print_diag("SQLFreeHandle failed", SQL_HANDLE_DBC, conn);
128 fflush(stdout);
129 exit(1);
130 }
131 conn = NULL;
132
133 rc = SQLFreeHandle(SQL_HANDLE_ENV, env);
134 if (!SQL_SUCCEEDED(rc))
135 {
136 print_diag("SQLFreeHandle failed", SQL_HANDLE_ENV, env);
137 fflush(stdout);
138 exit(1);
139 }
140 env = NULL;
141 }
142
143 const char *
datatype_str(SQLSMALLINT datatype)144 datatype_str(SQLSMALLINT datatype)
145 {
146 static char buf[100];
147
148 switch (datatype)
149 {
150 case SQL_CHAR:
151 return "CHAR";
152 case SQL_VARCHAR:
153 return "VARCHAR";
154 case SQL_LONGVARCHAR:
155 return "LONGVARCHAR";
156 case SQL_WCHAR:
157 return "WCHAR";
158 case SQL_WVARCHAR:
159 return "WVARCHAR";
160 case SQL_WLONGVARCHAR:
161 return "WLONGVARCHAR";
162 case SQL_DECIMAL:
163 return "DECIMAL";
164 case SQL_NUMERIC:
165 return "NUMERIC";
166 case SQL_SMALLINT:
167 return "SMALLINT";
168 case SQL_INTEGER:
169 return "INTEGER";
170 case SQL_REAL:
171 return "REAL";
172 case SQL_FLOAT:
173 return "FLOAT";
174 case SQL_DOUBLE:
175 return "DOUBLE";
176 case SQL_BIT:
177 return "BIT";
178 case SQL_TINYINT:
179 return "TINYINT";
180 case SQL_BIGINT:
181 return "BIGINT";
182 case SQL_BINARY:
183 return "BINARY";
184 case SQL_VARBINARY:
185 return "VARBINARY";
186 case SQL_LONGVARBINARY:
187 return "LONGVARBINARY";
188 case SQL_TYPE_DATE:
189 return "TYPE_DATE";
190 case SQL_TYPE_TIME:
191 return "TYPE_TIME";
192 case SQL_TYPE_TIMESTAMP:
193 return "TYPE_TIMESTAMP";
194 case SQL_GUID:
195 return "GUID";
196 default:
197 snprintf(buf, sizeof(buf), "unknown sql type %d", datatype);
198 return buf;
199 }
200 }
201
nullable_str(SQLSMALLINT nullable)202 const char *nullable_str(SQLSMALLINT nullable)
203 {
204 static char buf[100];
205
206 switch(nullable)
207 {
208 case SQL_NO_NULLS:
209 return "not nullable";
210 case SQL_NULLABLE:
211 return "nullable";
212 case SQL_NULLABLE_UNKNOWN:
213 return "nullable_unknown";
214 default:
215 snprintf(buf, sizeof(buf), "unknown nullable value %d", nullable);
216 return buf;
217 }
218 }
219
220 void
print_result_meta_series(HSTMT hstmt,SQLSMALLINT * colids,SQLSMALLINT numcols)221 print_result_meta_series(HSTMT hstmt,
222 SQLSMALLINT *colids,
223 SQLSMALLINT numcols)
224 {
225 int i;
226
227 printf("Result set metadata:\n");
228
229 for (i = 0; i < numcols; i++)
230 {
231 SQLRETURN rc;
232 SQLCHAR colname[50];
233 SQLSMALLINT colnamelen;
234 SQLSMALLINT datatype;
235 SQLULEN colsize;
236 SQLSMALLINT decdigits;
237 SQLSMALLINT nullable;
238
239 rc = SQLDescribeCol(hstmt, colids[i],
240 colname, sizeof(colname),
241 &colnamelen,
242 &datatype,
243 &colsize,
244 &decdigits,
245 &nullable);
246 if (!SQL_SUCCEEDED(rc))
247 {
248 print_diag("SQLDescribeCol failed", SQL_HANDLE_STMT, hstmt);
249 return;
250 }
251 printf("%s: %s(%u) digits: %d, %s\n",
252 colname, datatype_str(datatype), (unsigned int) colsize,
253 decdigits, nullable_str(nullable));
254 }
255 }
256
257 void
print_result_meta(HSTMT hstmt)258 print_result_meta(HSTMT hstmt)
259 {
260 SQLRETURN rc;
261 SQLSMALLINT numcols, i;
262 SQLSMALLINT *colids;
263
264 rc = SQLNumResultCols(hstmt, &numcols);
265 if (!SQL_SUCCEEDED(rc))
266 {
267 print_diag("SQLNumResultCols failed", SQL_HANDLE_STMT, hstmt);
268 return;
269 }
270
271 colids = (SQLSMALLINT *) malloc(numcols * sizeof(SQLSMALLINT));
272 for (i = 0; i < numcols; i++)
273 colids[i] = i + 1;
274 print_result_meta_series(hstmt, colids, numcols);
275 free(colids);
276 }
277
278 /*
279 * Initialize a buffer with "XxXxXx..." to indicate an uninitialized value.
280 */
281 static void
invalidate_buf(char * buf,size_t len)282 invalidate_buf(char *buf, size_t len)
283 {
284 size_t i;
285
286 for (i = 0; i < len; i++)
287 {
288 if (i % 2 == 0)
289 buf[i] = 'X';
290 else
291 buf[i] = 'x';
292 }
293 buf[len - 1] = '\0';
294 }
295
296 /*
297 * Print result only for the selected columns.
298 */
299 void
print_result_series(HSTMT hstmt,SQLSMALLINT * colids,SQLSMALLINT numcols,SQLINTEGER rowcount)300 print_result_series(HSTMT hstmt, SQLSMALLINT *colids, SQLSMALLINT numcols, SQLINTEGER rowcount)
301 {
302 SQLRETURN rc;
303 SQLINTEGER rowc = 0;
304
305 printf("Result set:\n");
306 while (rowcount <0 || rowc < rowcount)
307 {
308 rc = SQLFetch(hstmt);
309 if (rc == SQL_NO_DATA)
310 break;
311 if (rc == SQL_SUCCESS)
312 {
313 char buf[40];
314 int i;
315 SQLLEN ind;
316
317 rowc++;
318 for (i = 0; i < numcols; i++)
319 {
320 /*
321 * Initialize the buffer with garbage, so that we see readily
322 * if SQLGetData fails to set the value properly or forgets
323 * to null-terminate it.
324 */
325 invalidate_buf(buf, sizeof(buf));
326 rc = SQLGetData(hstmt, colids[i], SQL_C_CHAR, buf, sizeof(buf), &ind);
327 if (!SQL_SUCCEEDED(rc))
328 {
329 print_diag("SQLGetData failed", SQL_HANDLE_STMT, hstmt);
330 return;
331 }
332 if (ind == SQL_NULL_DATA)
333 strcpy(buf, "NULL");
334 printf("%s%s", (i > 0) ? "\t" : "", buf);
335 }
336 printf("\n");
337 }
338 else
339 {
340 print_diag("SQLFetch failed", SQL_HANDLE_STMT, hstmt);
341 fflush(stdout);
342 exit(1);
343 }
344 }
345 }
346
347 /*
348 * Print result on all the columns
349 */
350 void
print_result(HSTMT hstmt)351 print_result(HSTMT hstmt)
352 {
353 SQLRETURN rc;
354 SQLSMALLINT numcols, i;
355 SQLSMALLINT *colids;
356
357 rc = SQLNumResultCols(hstmt, &numcols);
358 if (!SQL_SUCCEEDED(rc))
359 {
360 print_diag("SQLNumResultCols failed", SQL_HANDLE_STMT, hstmt);
361 return;
362 }
363
364 colids = (SQLSMALLINT *) malloc(numcols * sizeof(SQLSMALLINT));
365 for (i = 0; i < numcols; i++)
366 colids[i] = i + 1;
367 print_result_series(hstmt, colids, numcols, -1);
368 free(colids);
369 }
370