Line data Source code
1 : #include "common.h"
2 :
3 : #include <stdarg.h>
4 : #include <assert.h>
5 : #include <ctype.h>
6 :
7 : #if HAVE_SYS_SOCKET_H
8 : #include <sys/socket.h>
9 : #endif /* HAVE_SYS_SOCKET_H */
10 :
11 : #if HAVE_SYS_STAT_H
12 : #include <sys/stat.h>
13 : #endif /* HAVE_SYS_STAT_H */
14 :
15 : #if HAVE_NETINET_IN_H
16 : #include <netinet/in.h>
17 : #endif /* HAVE_NETINET_IN_H */
18 :
19 : #if defined(UNIXODBC) || defined(_WIN32)
20 : #include <odbcinst.h>
21 : #endif
22 :
23 : #include <odbcss.h>
24 : #include <freetds/sysdep_private.h>
25 : #include <freetds/replacements.h>
26 :
27 : struct odbc_buf{
28 : struct odbc_buf *next;
29 : void *buf;
30 : };
31 :
32 : HENV odbc_env;
33 : HDBC odbc_conn;
34 : HSTMT odbc_stmt;
35 : bool odbc_use_version3 = false;
36 : void (*odbc_set_conn_attr)(void) = NULL;
37 : const char *odbc_conn_additional_params = NULL;
38 :
39 : static int freetds_driver = -1;
40 : static int tds_version = -1;
41 : static char db_str_version[32];
42 :
43 : static bool
44 1126 : check_lib(char *path, const char *file)
45 : {
46 1126 : size_t len = strlen(path);
47 : FILE *f;
48 :
49 1126 : strcat(path, file);
50 1126 : f = fopen(path, "rb");
51 1126 : if (f) {
52 1126 : fclose(f);
53 1126 : return true;
54 : }
55 0 : path[len] = 0;
56 0 : return false;
57 : }
58 :
59 : /* this should be extended with all possible systems... */
60 : static const char *const search_driver[] = {
61 : ".libs/libtdsodbc.so",
62 : ".libs/libtdsodbc.sl",
63 : ".libs/libtdsodbc.dylib",
64 : ".libs/libtdsodbc.dll",
65 : "_libs/libtdsodbc.dll",
66 : "_libs/libtdsodbc.exe", /* VMS */
67 : "debug/tdsodbc.dll",
68 : "release/tdsodbc.dll",
69 : "libtdsodbc.so",
70 : "tdsodbc.dll",
71 : NULL
72 : };
73 :
74 : int
75 1126 : odbc_read_login_info(void)
76 : {
77 1126 : const char *PWD = DEFAULT_PWD_PATH;
78 : #if !defined(_WIN32) || defined(TDS_NO_DM)
79 1126 : FILE *in = NULL;
80 : #endif
81 : char *s1;
82 : const char *const *search_p;
83 : char path[1024];
84 : size_t len;
85 1126 : bool ini_override = true;
86 : #if defined(_WIN32) && !defined(TDS_NO_DM)
87 : UWORD old_config_mode;
88 : #endif
89 :
90 1126 : setbuf(stdout, NULL);
91 1126 : setbuf(stderr, NULL);
92 :
93 1126 : PWD = try_read_login_info_base(&common_pwd, PWD);
94 1126 : if (!PWD && !read_login_info_base(&common_pwd, "PWD"))
95 : return 1;
96 :
97 : /*
98 : * Some of the ODBC tests "go in the front door", i.e. call
99 : * SQLDriverConnect() which will look up an entry in ODBCINST.INI .
100 : * In "connect" and "timeout3" they look up the entry FreeTDS.
101 : * However your system ODBCINST.INI probably doesn't point to
102 : * the driver we just built and are trying to test.
103 : *
104 : * So here we are finding the ODBC driver we just built and saving it
105 : * into a custom field common_pwd.driver, and those tests have code to
106 : * build a dummy ODBCINST.INI with an entry called FreeTDS and using
107 : * common_pwd.driver sa the driver.
108 : */
109 : #ifndef _WIN32
110 1126 : if (!getcwd(path, sizeof(path)))
111 : #else
112 : if (!_getcwd(path, sizeof(path)))
113 : #endif
114 : return 0;
115 : #ifdef __VMS
116 : {
117 : /* A hard-coded driver path has to be in unix syntax to be recognized as such. */
118 : const char *unixspec = decc$translate_vms(path);
119 : if ( (int)unixspec != 0 && (int)unixspec != -1 ) strcpy(path, unixspec);
120 : }
121 : #endif
122 1126 : len = strlen(path);
123 1126 : if (len < 10 || (strcasecmp(path + len - 10, "/unittests") != 0
124 : #ifdef _WIN32
125 : && strcasecmp(path + len - 10, "\\unittests") != 0
126 : #endif
127 : ))
128 : return 0;
129 1126 : path[len - 9] = 0;
130 1126 : for (search_p = search_driver; *search_p; ++search_p) {
131 1126 : if (check_lib(path, *search_p))
132 : break;
133 : }
134 1126 : if (!*search_p)
135 : return 0;
136 1126 : strcpy(common_pwd.driver, path);
137 :
138 1126 : s1 = getenv("TDSINIOVERRIDE");
139 1126 : if (s1 && atoi(s1) == 0)
140 0 : ini_override = false;
141 :
142 : #if !defined(_WIN32) || defined(TDS_NO_DM)
143 : /* craft out odbc.ini, avoid to read wrong one */
144 1126 : sprintf(path, "odbc.ini.%d", (int) getpid());
145 1126 : in = fopen(path, "w");
146 1126 : if (in) {
147 1126 : fprintf(in,
148 : "[%s]\nDriver = %s\nDatabase = %s\nServername = %s\n",
149 : common_pwd.server, common_pwd.driver, common_pwd.database, common_pwd.server);
150 1126 : fclose(in);
151 1126 : if (ini_override) {
152 1126 : setenv("ODBCINI", "./odbc.ini", 1);
153 1126 : setenv("SYSODBCINI", "./odbc.ini", 1);
154 1126 : rename(path, "odbc.ini");
155 : }
156 1126 : unlink(path);
157 : }
158 : #else
159 : if (ini_override && SQLGetConfigMode(&old_config_mode)) {
160 : ODBC_BUF *odbc_buf = NULL;
161 : LPCTSTR server = (LPCTSTR) T(common_pwd.server);
162 : LPCTSTR filename = (LPCTSTR) T("odbc.ini");
163 : SQLSetConfigMode(ODBC_USER_DSN);
164 : SQLWritePrivateProfileString(server, (LPCTSTR) T("Driver"), (void *) T(common_pwd.driver), filename);
165 : SQLWritePrivateProfileString(server, (LPCTSTR) T("Database"), (LPCTSTR) T(common_pwd.database), filename);
166 : SQLWritePrivateProfileString(server, (LPCTSTR) T("Servername"), (LPCTSTR) T(common_pwd.server), filename);
167 : SQLSetConfigMode(old_config_mode);
168 : ODBC_FREE();
169 : }
170 : #endif
171 : return 0;
172 : }
173 :
174 : void
175 0 : odbc_report_error(const char *errmsg, int line, const char *file)
176 : {
177 : SQLSMALLINT handletype;
178 : SQLHANDLE handle;
179 : SQLRETURN ret;
180 : SQLTCHAR sqlstate[6];
181 : SQLTCHAR msg[256];
182 0 : ODBC_BUF *odbc_buf = NULL;
183 :
184 0 : if (odbc_stmt) {
185 : handletype = SQL_HANDLE_STMT;
186 : handle = odbc_stmt;
187 0 : } else if (odbc_conn) {
188 : handletype = SQL_HANDLE_DBC;
189 : handle = odbc_conn;
190 : } else {
191 0 : handletype = SQL_HANDLE_ENV;
192 0 : handle = odbc_env;
193 : }
194 0 : if (errmsg[0]) {
195 0 : if (line)
196 0 : fprintf(stderr, "%s:%d %s\n", file, line, errmsg);
197 : else
198 0 : fprintf(stderr, "%s\n", errmsg);
199 : }
200 0 : ret = SQLGetDiagRec(handletype, handle, 1, sqlstate, NULL, msg, TDS_VECTOR_SIZE(msg), NULL);
201 0 : if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
202 0 : fprintf(stderr, "SQL error %s -- %s\n", C(sqlstate), C(msg));
203 0 : odbc_disconnect();
204 0 : ODBC_FREE();
205 0 : exit(1);
206 : }
207 :
208 : static void
209 0 : ReportODBCError(const char *errmsg, SQLSMALLINT handletype, SQLHANDLE handle, SQLRETURN rc, int line, const char *file)
210 : {
211 : SQLRETURN ret;
212 : SQLTCHAR sqlstate[6];
213 : SQLTCHAR msg[256];
214 0 : ODBC_BUF *odbc_buf = NULL;
215 :
216 0 : if (errmsg[0]) {
217 0 : if (line)
218 0 : fprintf(stderr, "%s:%d rc=%d %s\n", file, line, (int) rc, errmsg);
219 : else
220 0 : fprintf(stderr, "rc=%d %s\n", (int) rc, errmsg);
221 : }
222 0 : ret = SQLGetDiagRec(handletype, handle, 1, sqlstate, NULL, msg, TDS_VECTOR_SIZE(msg), NULL);
223 0 : if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
224 0 : fprintf(stderr, "SQL error %s -- %s\n", C(sqlstate), C(msg));
225 0 : odbc_disconnect();
226 0 : ODBC_FREE();
227 0 : exit(1);
228 : }
229 :
230 : int
231 1076 : odbc_connect(void)
232 : {
233 1076 : ODBC_BUF *odbc_buf = NULL;
234 : char command[512+10];
235 : const char *p;
236 :
237 1076 : if (odbc_read_login_info())
238 0 : exit(1);
239 :
240 1076 : if (odbc_use_version3) {
241 576 : CHKAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &odbc_env, "S");
242 576 : SQLSetEnvAttr(odbc_env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) (SQL_OV_ODBC3), SQL_IS_UINTEGER);
243 576 : CHKAllocHandle(SQL_HANDLE_DBC, odbc_env, &odbc_conn, "S");
244 : } else {
245 500 : CHKAllocEnv(&odbc_env, "S");
246 500 : CHKAllocConnect(&odbc_conn, "S");
247 : }
248 :
249 1076 : printf("odbctest\n--------\n\n");
250 1076 : printf("connection parameters:\nserver: '%s'\nuser: '%s'\npassword: '%s'\ndatabase: '%s'\n",
251 : common_pwd.server, common_pwd.user, "????" /* common_pwd.password */ , common_pwd.database);
252 :
253 1076 : p = getenv("ODBC_MARS");
254 1614 : if (p && atoi(p) != 0)
255 538 : SQLSetConnectAttr(odbc_conn, 1224 /*SQL_COPT_SS_MARS_ENABLED*/, (SQLPOINTER) 1 /*SQL_MARS_ENABLED_YES*/, SQL_IS_UINTEGER);
256 1076 : if (odbc_set_conn_attr)
257 64 : (*odbc_set_conn_attr)();
258 :
259 1076 : if (!odbc_conn_additional_params) {
260 996 : CHKConnect(T(common_pwd.server), SQL_NTS, T(common_pwd.user), SQL_NTS, T(common_pwd.password), SQL_NTS, "SI");
261 : } else {
262 : char *params;
263 : SQLSMALLINT len;
264 :
265 80 : assert(asprintf(¶ms, "DSN=%s;UID=%s;PWD=%s;DATABASE=%s;%s",
266 : common_pwd.server, common_pwd.user,
267 : common_pwd.password, common_pwd.database, odbc_conn_additional_params)
268 : >= 0);
269 80 : assert(params);
270 80 : CHKDriverConnect(NULL, T(params), SQL_NTS, (SQLTCHAR *) command, sizeof(command)/sizeof(SQLTCHAR),
271 : &len, SQL_DRIVER_NOPROMPT, "SI");
272 80 : free(params);
273 : }
274 :
275 1076 : CHKAllocStmt(&odbc_stmt, "S");
276 :
277 1076 : sprintf(command, "use %s", common_pwd.database);
278 1076 : printf("%s\n", command);
279 :
280 1076 : CHKExecDirect(T(command), SQL_NTS, "SI");
281 :
282 : #ifndef TDS_NO_DM
283 : /* unixODBC seems to require it */
284 : SQLMoreResults(odbc_stmt);
285 : #endif
286 1076 : ODBC_FREE();
287 1076 : return 0;
288 : }
289 :
290 : int
291 1186 : odbc_disconnect(void)
292 : {
293 1186 : if (odbc_stmt) {
294 1078 : SQLFreeStmt(odbc_stmt, SQL_DROP);
295 1078 : odbc_stmt = SQL_NULL_HSTMT;
296 : }
297 :
298 1186 : if (odbc_conn) {
299 1186 : SQLDisconnect(odbc_conn);
300 1186 : SQLFreeConnect(odbc_conn);
301 1186 : odbc_conn = SQL_NULL_HDBC;
302 : }
303 :
304 1186 : ODBC_FREE();
305 1186 : if (odbc_env) {
306 1186 : SQLFreeEnv(odbc_env);
307 1186 : odbc_env = SQL_NULL_HENV;
308 : }
309 1186 : ODBC_FREE();
310 :
311 1186 : freetds_driver = -1;
312 1186 : tds_version = -1;
313 1186 : db_str_version[0] = 0;
314 1186 : return 0;
315 : }
316 :
317 : SQLRETURN
318 1050 : odbc_command_with_result(HSTMT stmt, const char *command)
319 : {
320 : SQLRETURN ret;
321 1050 : ODBC_BUF *odbc_buf = NULL;
322 :
323 1050 : printf("%s\n", command);
324 1050 : ret = SQLExecDirect(stmt, T(command), SQL_NTS);
325 1050 : ODBC_FREE();
326 1050 : return ret;
327 : }
328 :
329 : static int ms_db = -1;
330 : bool
331 2930 : odbc_db_is_microsoft(void)
332 : {
333 2930 : ODBC_BUF *odbc_buf = NULL;
334 : SQLTCHAR buf[64];
335 : SQLSMALLINT len;
336 : int i;
337 :
338 2930 : if (ms_db < 0) {
339 268 : buf[0] = 0;
340 268 : CHKGetInfo(SQL_DBMS_NAME, buf, sizeof(buf), &len, "S");
341 5128 : for (i = 0; buf[i]; ++i)
342 7200 : buf[i] = tolower(buf[i]);
343 268 : ms_db = (strstr(C(buf), "microsoft") != NULL);
344 : }
345 2930 : ODBC_FREE();
346 2930 : return !!ms_db;
347 : }
348 :
349 : bool
350 1646 : odbc_driver_is_freetds(void)
351 : {
352 1646 : ODBC_BUF *odbc_buf = NULL;
353 : SQLTCHAR buf[64];
354 : SQLSMALLINT len;
355 : int i;
356 :
357 1646 : if (freetds_driver < 0) {
358 336 : buf[0] = 0;
359 336 : CHKGetInfo(SQL_DRIVER_NAME, buf, sizeof(buf), &len, "S");
360 4704 : for (i = 0; buf[i]; ++i)
361 6487 : buf[i] = tolower(buf[i]);
362 336 : freetds_driver = (strstr(C(buf), "tds") != NULL);
363 : }
364 1646 : ODBC_FREE();
365 1646 : return !!freetds_driver;
366 : }
367 :
368 : /* Detect protocol version using queries
369 : * This to make possible protocol discovery on drivers like MS
370 : */
371 : static int
372 0 : odbc_tds_version_long(void)
373 : {
374 : SQLRETURN ret;
375 : SQLSMALLINT scale, nullable, type;
376 : SQLULEN prec;
377 0 : ODBC_BUF *odbc_buf = NULL;
378 :
379 : /* statement must be in a consistent state to do the check */
380 0 : CHKExecDirect(T("select 1"), SQL_NTS, "S");
381 0 : odbc_reset_statement();
382 :
383 : /* select cast(123 as sql_variant) -> nvarchar('123') is 7.0 failure query is 5.0 ?? */
384 0 : ret = CHKExecDirect(T("select cast('123' as sql_variant)"), SQL_NTS, "SNoE");
385 0 : odbc_reset_statement();
386 0 : if (ret == SQL_ERROR) {
387 0 : ODBC_FREE();
388 0 : return 0x500;
389 : }
390 :
391 : /* see how bigint is returned, numeric means 7.0 */
392 0 : CHKExecDirect(T("select cast('123' as bigint)"), SQL_NTS, "S");
393 0 : CHKDescribeCol(1, NULL, 0, NULL, &type, &prec, &scale, &nullable, "S");
394 0 : odbc_reset_statement();
395 0 : if (type == SQL_NUMERIC || type == SQL_DECIMAL) {
396 0 : ODBC_FREE();
397 0 : return 0x700;
398 : }
399 0 : if (type != SQL_BIGINT) {
400 0 : fprintf(stderr, "Strange type returned trying to detect protocol version\n");
401 0 : odbc_disconnect();
402 0 : ODBC_FREE();
403 0 : exit(1);
404 : }
405 :
406 : /* select cast('123' as varchar(max)) -> ??? SQL_VARCHAR is 7.2 ?? */
407 0 : ret = CHKExecDirect(T("select cast('123' as varchar(max))"), SQL_NTS, "SE");
408 0 : if (ret == SQL_ERROR) {
409 0 : odbc_reset_statement();
410 0 : ODBC_FREE();
411 0 : return 0x701;
412 : }
413 0 : CHKDescribeCol(1, NULL, 0, NULL, &type, &prec, &scale, &nullable, "S");
414 0 : odbc_reset_statement();
415 0 : if (type == SQL_LONGVARCHAR) {
416 0 : ODBC_FREE();
417 0 : return 0x701;
418 : }
419 0 : if (type != SQL_VARCHAR) {
420 0 : fprintf(stderr, "Strange type returned trying to detect protocol version\n");
421 0 : odbc_disconnect();
422 0 : ODBC_FREE();
423 0 : exit(1);
424 : }
425 :
426 : /* select cast('12:13:14.1234' as time(4)) -> NVARCHAR('12:13:14.1234') is 7.2 else 7.3 */
427 0 : ret = CHKExecDirect(T("select cast('12:13:14.1234' as time(4))"), SQL_NTS, "SE");
428 0 : if (ret == SQL_ERROR) {
429 0 : odbc_reset_statement();
430 0 : ODBC_FREE();
431 0 : return 0x702;
432 : }
433 0 : CHKDescribeCol(1, NULL, 0, NULL, &type, &prec, &scale, &nullable, "S");
434 0 : odbc_reset_statement();
435 0 : if (scale == 4)
436 : return 0x703;
437 0 : if (scale != 0 || type != SQL_WVARCHAR) {
438 0 : fprintf(stderr, "Strange type or scale returned trying to detect protocol version\n");
439 0 : odbc_disconnect();
440 0 : ODBC_FREE();
441 0 : exit(1);
442 : }
443 :
444 0 : ODBC_FREE();
445 0 : return 0x702;
446 : }
447 :
448 : int
449 266 : odbc_tds_version(void)
450 : {
451 266 : ODBC_BUF *odbc_buf = NULL;
452 : SQLUINTEGER version;
453 : SQLSMALLINT len;
454 :
455 266 : if (odbc_driver_is_freetds() && tds_version < 0) {
456 122 : version = 0;
457 122 : len = 0;
458 122 : CHKGetInfo(1300 /* SQL_INFO_FREETDS_TDS_VERSION */, &version, sizeof(version), &len, "S");
459 122 : if (len == sizeof(version))
460 122 : tds_version = (version >> 16) << 8 | (version & 0xff);
461 : }
462 266 : if (tds_version < 0) {
463 0 : tds_version = odbc_tds_version_long();
464 : }
465 266 : ODBC_FREE();
466 266 : return tds_version;
467 : }
468 :
469 : const char *
470 350 : odbc_db_version(void)
471 : {
472 350 : if (!db_str_version[0]) {
473 90 : ODBC_BUF *odbc_buf = NULL;
474 : SQLTCHAR buf[32];
475 : SQLSMALLINT version_len;
476 :
477 90 : CHKGetInfo(SQL_DBMS_VER, buf, sizeof(buf), &version_len, "S");
478 90 : strcpy(db_str_version, C(buf));
479 90 : ODBC_FREE();
480 : }
481 :
482 350 : return db_str_version;
483 : }
484 :
485 : unsigned int
486 340 : odbc_db_version_int(void)
487 : {
488 : unsigned int h, l;
489 340 : if (sscanf(odbc_db_version(), "%u.%u.", &h, &l) != 2) {
490 0 : fprintf(stderr, "Wrong db version: %s\n", odbc_db_version());
491 0 : odbc_disconnect();
492 0 : exit(1);
493 : }
494 :
495 340 : return (h << 24) | ((l & 0xFFu) << 16);
496 : }
497 :
498 : void
499 268 : odbc_check_cols(int n, int line, const char * file)
500 : {
501 : SQLSMALLINT cols;
502 :
503 268 : if (n < 0) {
504 0 : CHKNumResultCols(&cols, "E");
505 0 : return;
506 : }
507 268 : CHKNumResultCols(&cols, "S");
508 268 : if (cols != n) {
509 0 : fprintf(stderr, "%s:%d: Expected %d columns returned %d\n", file, line, n, (int) cols);
510 0 : odbc_disconnect();
511 0 : exit(1);
512 : }
513 : }
514 :
515 : void
516 570 : odbc_check_rows(int n, int line, const char * file)
517 : {
518 : SQLLEN rows;
519 :
520 570 : if (n < -1) {
521 0 : CHKRowCount(&rows, "E");
522 0 : return;
523 : }
524 :
525 570 : CHKRowCount(&rows, "S");
526 570 : if (rows != n) {
527 0 : fprintf(stderr, "%s:%d: Expected %d rows returned %d\n", file, line, n, (int) rows);
528 0 : odbc_disconnect();
529 0 : exit(1);
530 : }
531 : }
532 :
533 : void
534 16260 : odbc_reset_statement_proc(SQLHSTMT *stmt, const char *file, int line)
535 : {
536 16260 : SQLFreeStmt(*stmt, SQL_DROP);
537 16260 : *stmt = SQL_NULL_HSTMT;
538 16260 : odbc_check_res(file, line, SQLAllocStmt(odbc_conn, stmt), SQL_HANDLE_DBC, odbc_conn, "SQLAllocStmt", "S");
539 16260 : }
540 :
541 : void
542 68 : odbc_test_skipped(void)
543 : {
544 68 : const char *p = getenv("TDS_SKIP_SUCCESS");
545 70 : if (p && atoi(p) != 0)
546 2 : exit(0);
547 66 : exit(77);
548 : }
549 :
550 : void
551 130 : odbc_check_cursor(void)
552 : {
553 : SQLRETURN retcode;
554 130 : ODBC_BUF *odbc_buf = NULL;
555 :
556 130 : retcode = SQLSetStmtAttr(odbc_stmt, SQL_ATTR_CONCURRENCY, (SQLPOINTER) SQL_CONCUR_ROWVER, 0);
557 130 : if (retcode != SQL_SUCCESS) {
558 : SQLTCHAR output[256];
559 : SQLTCHAR sqlstate[6];
560 :
561 26 : CHKGetDiagRec(SQL_HANDLE_STMT, odbc_stmt, 1, sqlstate, NULL, output, TDS_VECTOR_SIZE(output), NULL, "S");
562 26 : sqlstate[5] = 0;
563 26 : if (strcmp(C(sqlstate), "01S02") == 0) {
564 26 : printf("Your connection seems to not support cursors, probably you are using wrong protocol version or Sybase\n");
565 26 : odbc_disconnect();
566 26 : ODBC_FREE();
567 26 : odbc_test_skipped();
568 : }
569 0 : ReportODBCError("SQLSetStmtAttr", SQL_HANDLE_STMT, odbc_stmt, retcode, __LINE__, __FILE__);
570 : }
571 104 : odbc_reset_statement();
572 104 : ODBC_FREE();
573 104 : }
574 :
575 : SQLRETURN
576 142112 : odbc_check_res(const char *file, int line, SQLRETURN rc, SQLSMALLINT handle_type, SQLHANDLE handle, const char *func, const char *res)
577 : {
578 142112 : const char *p = res;
579 : for (;;) {
580 159665 : if (*p == 'S') {
581 123936 : if (rc == SQL_SUCCESS)
582 : return rc;
583 16201 : ++p;
584 35729 : } else if (*p == 'I') {
585 4292 : if (rc == SQL_SUCCESS_WITH_INFO)
586 : return rc;
587 1116 : ++p;
588 31437 : } else if (*p == 'E') {
589 1601 : if (rc == SQL_ERROR)
590 : return rc;
591 234 : ++p;
592 29836 : } else if (strncmp(p, "No", 2) == 0) {
593 29332 : if (rc == SQL_NO_DATA)
594 : return rc;
595 2 : p += 2;
596 504 : } else if (strncmp(p, "Ne", 2) == 0) {
597 464 : if (rc == SQL_NEED_DATA)
598 : return rc;
599 0 : p += 2;
600 40 : } else if (*p == 'V') {
601 40 : if (rc == SQL_INVALID_HANDLE)
602 : return rc;
603 0 : ++p;
604 0 : } else if (!*p) {
605 : break;
606 : } else {
607 0 : odbc_report_error("Wrong results specified", line, file);
608 : return rc;
609 : }
610 : }
611 0 : ReportODBCError(func, handle_type, handle, rc, line, file);
612 : return rc;
613 : }
614 :
615 : SQLSMALLINT
616 184 : odbc_alloc_handle_err_type(SQLSMALLINT type)
617 : {
618 184 : switch (type) {
619 : case SQL_HANDLE_DESC:
620 : return SQL_HANDLE_STMT;
621 : case SQL_HANDLE_STMT:
622 : return SQL_HANDLE_DBC;
623 : case SQL_HANDLE_DBC:
624 : return SQL_HANDLE_ENV;
625 : }
626 : return 0;
627 : }
628 :
629 : SQLRETURN
630 22672 : odbc_command_proc(HSTMT stmt, const char *command, const char *file, int line, const char *res)
631 : {
632 : SQLRETURN ret;
633 22672 : ODBC_BUF *odbc_buf = NULL;
634 :
635 22672 : if (command[0] == '@')
636 40 : ++command;
637 : else
638 22632 : printf("%s\n", command);
639 :
640 22672 : ret = odbc_check_res(file, line, SQLExecDirect(stmt, T(command), SQL_NTS), SQL_HANDLE_STMT, stmt, "odbc_command", res);
641 22672 : ODBC_FREE();
642 22672 : return ret;
643 : }
644 :
645 : char odbc_err[512];
646 : char odbc_sqlstate[6];
647 :
648 : void
649 259 : odbc_read_error(void)
650 : {
651 259 : ODBC_BUF *odbc_buf = NULL;
652 259 : SQLTCHAR *err = (SQLTCHAR *) ODBC_GET(sizeof(odbc_err)*sizeof(SQLTCHAR));
653 259 : SQLTCHAR *state = (SQLTCHAR *) ODBC_GET(sizeof(odbc_sqlstate)*sizeof(SQLTCHAR));
654 :
655 259 : memset(odbc_err, 0, sizeof(odbc_err));
656 259 : memset(odbc_sqlstate, 0, sizeof(odbc_sqlstate));
657 259 : if (odbc_stmt != SQL_NULL_HSTMT)
658 257 : CHKGetDiagRec(SQL_HANDLE_STMT, odbc_stmt, 1, state, NULL, err, sizeof(odbc_err), NULL, "SI");
659 : else
660 2 : CHKGetDiagRec(SQL_HANDLE_DBC, odbc_conn, 1, state, NULL, err, sizeof(odbc_err), NULL, "SI");
661 259 : strcpy(odbc_err, C(err));
662 259 : strcpy(odbc_sqlstate, C(state));
663 259 : ODBC_FREE();
664 259 : printf("Message: '%s' %s\n", odbc_sqlstate, odbc_err);
665 259 : }
666 :
667 : SQLLEN
668 64 : odbc_to_sqlwchar(SQLWCHAR *dst, const char *src, SQLLEN n)
669 : {
670 64 : SQLLEN i = n;
671 1933686 : while (--i >= 0)
672 1915868 : dst[i] = (unsigned char) src[i];
673 64 : return n * sizeof(SQLWCHAR);
674 : }
675 :
676 : SQLLEN
677 4362 : odbc_from_sqlwchar(char *dst, const SQLWCHAR *src, SQLLEN n)
678 : {
679 : SQLLEN i;
680 4362 : if (n < 0) {
681 : const SQLWCHAR *p = src;
682 0 : for (n=1; *p++ != 0; ++n)
683 0 : continue;
684 : }
685 2327707 : for (i = 0; i < n; ++i) {
686 2323345 : assert(src[i] < 256);
687 2323345 : dst[i] = (char) src[i];
688 : }
689 4362 : return n;
690 : }
691 :
692 : ODBC_BUF *odbc_buf = NULL;
693 :
694 : void *
695 23840 : odbc_buf_add(ODBC_BUF** buf, void *ptr)
696 : {
697 23840 : ODBC_BUF *p = (ODBC_BUF*) calloc(1, sizeof(ODBC_BUF));
698 23840 : assert(ptr);
699 23840 : assert(p);
700 23840 : p->buf = ptr;
701 23840 : p->next = *buf;
702 23840 : *buf = p;
703 23840 : return p->buf;
704 : }
705 :
706 : void *
707 1380 : odbc_buf_get(ODBC_BUF** buf, size_t s)
708 : {
709 23390 : return odbc_buf_add(buf, malloc(s));
710 : }
711 :
712 : void
713 44915 : odbc_buf_free(ODBC_BUF** buf)
714 : {
715 44915 : ODBC_BUF *cur = *buf;
716 44915 : *buf = NULL;
717 113670 : while (cur) {
718 23840 : ODBC_BUF *next = cur->next;
719 23840 : free(cur->buf);
720 23840 : free(cur);
721 23840 : cur = next;
722 : }
723 44915 : }
724 :
725 : SQLWCHAR *
726 17858 : odbc_get_sqlwchar(ODBC_BUF** buf, const char *s)
727 : {
728 : size_t l;
729 : SQLWCHAR *buffer;
730 :
731 17858 : if (!s) return NULL;
732 17690 : l = strlen(s) + 1;
733 35380 : buffer = (SQLWCHAR*) odbc_buf_get(buf, l * sizeof(SQLWCHAR));
734 17690 : odbc_to_sqlwchar(buffer, s, l);
735 : return buffer;
736 : }
737 :
738 : char*
739 3802 : odbc_get_sqlchar(ODBC_BUF** buf, SQLWCHAR *s)
740 : {
741 : int n;
742 3802 : const SQLWCHAR *p = s;
743 : char *out;
744 :
745 82785 : for (n=1; *p++ != 0; ++n)
746 78983 : continue;
747 7604 : out = (char *) odbc_buf_get(buf, n);
748 3802 : odbc_from_sqlwchar(out, s, n);
749 3802 : return out;
750 : }
751 :
752 : char *
753 450 : odbc_buf_asprintf(ODBC_BUF** buf, const char *fmt, ...)
754 : {
755 : va_list ap;
756 450 : char *ret = NULL;
757 :
758 450 : va_start(ap, fmt);
759 450 : assert(vasprintf(&ret, fmt, ap) >= 0);
760 450 : va_end(ap);
761 :
762 450 : return (char *) odbc_buf_add(buf, ret);
763 : }
764 :
765 : typedef union {
766 : struct sockaddr sa;
767 : struct sockaddr_in sin;
768 : char dummy[256];
769 : } long_sockaddr;
770 :
771 : static int
772 81680 : fd_is_socket(int fd)
773 : {
774 : long_sockaddr addr;
775 : socklen_t addr_len;
776 :
777 : #ifndef _WIN32
778 : struct stat file_stat;
779 :
780 81680 : if (fstat(fd, &file_stat))
781 : return 0;
782 104 : if ((file_stat.st_mode & S_IFSOCK) != S_IFSOCK)
783 : return 0;
784 : #endif
785 :
786 0 : addr_len = sizeof(addr);
787 0 : if (tds_getpeername((TDS_SYS_SOCKET) fd, &addr.sa, &addr_len))
788 : return 0;
789 :
790 0 : addr_len = sizeof(addr);
791 0 : if (tds_getsockname((TDS_SYS_SOCKET) fd, &addr.sa, &addr_len))
792 : return 0;
793 :
794 0 : return 1;
795 : }
796 :
797 : enum {NUM_FDS = 4096*4};
798 : static unsigned char fd_bitmask[NUM_FDS / 8];
799 :
800 : static int
801 : mark_fd(int fd)
802 : {
803 : unsigned shift;
804 : unsigned char mask;
805 :
806 0 : if (fd < 0 || fd >= NUM_FDS)
807 : return 0;
808 :
809 0 : shift = fd & 7;
810 0 : mask = fd_bitmask[fd >> 3];
811 0 : fd_bitmask[fd >> 3] = mask | (1 << shift);
812 :
813 0 : return (mask >> shift) & 1;
814 : }
815 :
816 : #ifdef _WIN32
817 : #define FOR_ALL_SOCKETS(i) for (i = 4; i <= (4096*4); i += 4)
818 : #else
819 : #define FOR_ALL_SOCKETS(i) for (i = 3; i < 1024; ++i)
820 : #endif
821 :
822 : void
823 80 : odbc_mark_sockets_opened(void)
824 : {
825 : int i;
826 :
827 80 : memset(fd_bitmask, 0, sizeof(fd_bitmask));
828 81760 : FOR_ALL_SOCKETS(i) {
829 81680 : if (fd_is_socket(i))
830 : mark_fd(i);
831 : }
832 80 : }
833 :
834 : TDS_SYS_SOCKET
835 80 : odbc_find_last_socket(void)
836 : {
837 : typedef struct {
838 : TDS_SYS_SOCKET sock;
839 : int local_port;
840 : int remote_port;
841 : } sock_info;
842 : sock_info found[8];
843 80 : unsigned num_found = 0, n;
844 : int i;
845 :
846 80 : SQLULEN sock = 0;
847 : SQLSMALLINT len;
848 80 : if (odbc_driver_is_freetds()
849 80 : && SQLGetInfo(odbc_conn, 1301 /* SQL_INFO_FREETDS_SOCKET */, &sock, sizeof(sock), &len) == SQL_SUCCESS
850 80 : && len == sizeof(sock))
851 80 : return (TDS_SYS_SOCKET) sock;
852 :
853 0 : FOR_ALL_SOCKETS(i) {
854 : long_sockaddr remote_addr, local_addr;
855 : struct sockaddr_in *in;
856 : socklen_t remote_addr_len, local_addr_len;
857 : sock_info *info;
858 :
859 : /* check if is a socket */
860 0 : if (!fd_is_socket(i))
861 0 : continue;
862 0 : if (mark_fd(i))
863 0 : continue;
864 :
865 0 : remote_addr_len = sizeof(remote_addr);
866 0 : if (tds_getpeername((TDS_SYS_SOCKET) i, &remote_addr.sa, &remote_addr_len))
867 0 : continue;
868 0 : if (remote_addr.sa.sa_family != AF_INET
869 : #ifdef AF_INET6
870 0 : && remote_addr.sa.sa_family != AF_INET6
871 : #endif
872 : )
873 0 : continue;
874 0 : local_addr_len = sizeof(local_addr);
875 0 : if (tds_getsockname((TDS_SYS_SOCKET) i, &local_addr.sa, &local_addr_len))
876 0 : continue;
877 :
878 : /* save in the array */
879 0 : if (num_found >= 8) {
880 0 : memmove(found, found+1, sizeof(found) - sizeof(found[0]));
881 0 : num_found = 7;
882 : }
883 0 : info = &found[num_found++];
884 0 : info->sock = (TDS_SYS_SOCKET) i;
885 0 : info->local_port = -1;
886 0 : info->remote_port = -1;
887 :
888 : /* now check if is a socketpair */
889 0 : in = &remote_addr.sin;
890 0 : if (in->sin_family != AF_INET)
891 0 : continue;
892 0 : if (in->sin_addr.s_addr != htonl(INADDR_LOOPBACK))
893 0 : continue;
894 0 : info->remote_port = ntohs(in->sin_port);
895 0 : in = &local_addr.sin;
896 0 : if (in->sin_family != AF_INET)
897 0 : continue;
898 0 : if (in->sin_addr.s_addr != htonl(INADDR_LOOPBACK))
899 0 : continue;
900 0 : info->local_port = ntohs(in->sin_port);
901 0 : for (n = 0; n < num_found - 1; ++n) {
902 0 : if (found[n].remote_port != info->local_port
903 0 : || found[n].local_port != info->remote_port)
904 0 : continue;
905 0 : --num_found;
906 0 : memmove(found+n, found+n+1, num_found-n-1);
907 0 : --num_found;
908 0 : break;
909 : }
910 : }
911 :
912 : /* return last */
913 0 : if (num_found == 0)
914 : return INVALID_SOCKET;
915 0 : return found[num_found-1].sock;
916 : }
917 :
918 : void
919 732 : odbc_check_no_row(const char *query)
920 : {
921 : SQLRETURN rc;
922 :
923 732 : rc = CHKExecDirect(T(query), SQL_NTS, "SINo");
924 732 : if (rc == SQL_NO_DATA)
925 : return;
926 :
927 : do {
928 : SQLSMALLINT cols;
929 :
930 444 : CHKNumResultCols(&cols, "S");
931 444 : if (cols != 0) {
932 0 : fprintf(stderr, "Data not expected here, query:\n\t%s\n", query);
933 0 : odbc_disconnect();
934 0 : exit(1);
935 : }
936 444 : } while (CHKMoreResults("SNo") == SQL_SUCCESS);
937 : }
938 :
939 : int
940 1360 : odbc_lookup(const char *name, const struct odbc_lookup_int *table, int def)
941 : {
942 3790 : for (; table->name; ++table)
943 3790 : if (strcmp(table->name, name) == 0)
944 1360 : return table->value;
945 :
946 : return def;
947 : }
948 :
949 : const char*
950 250 : odbc_lookup_value(int value, const struct odbc_lookup_int *table, const char *def)
951 : {
952 4700 : for (; table->name; ++table)
953 4700 : if (table->value == value)
954 : return table->name;
955 :
956 : return def;
957 : }
958 :
959 : struct odbc_lookup_int odbc_sql_c_types[] = {
960 : #define TYPE(s) { #s, s }
961 : TYPE(SQL_C_NUMERIC),
962 : TYPE(SQL_C_BINARY),
963 : TYPE(SQL_C_CHAR),
964 : TYPE(SQL_C_WCHAR),
965 : TYPE(SQL_C_LONG),
966 : TYPE(SQL_C_SBIGINT),
967 : TYPE(SQL_C_SHORT),
968 : TYPE(SQL_C_TIMESTAMP),
969 : TYPE(SQL_C_FLOAT),
970 : TYPE(SQL_C_DOUBLE),
971 : TYPE(SQL_C_DEFAULT),
972 : TYPE(SQL_C_DATE),
973 : TYPE(SQL_C_TIME),
974 : TYPE(SQL_C_TYPE_DATE),
975 : TYPE(SQL_C_TYPE_TIME),
976 : TYPE(SQL_C_TYPE_TIMESTAMP),
977 : TYPE(SQL_C_INTERVAL_YEAR),
978 : TYPE(SQL_C_INTERVAL_MONTH),
979 : TYPE(SQL_C_INTERVAL_DAY),
980 : TYPE(SQL_C_INTERVAL_HOUR),
981 : TYPE(SQL_C_INTERVAL_MINUTE),
982 : TYPE(SQL_C_INTERVAL_SECOND),
983 : TYPE(SQL_C_INTERVAL_YEAR_TO_MONTH),
984 : TYPE(SQL_C_INTERVAL_DAY_TO_HOUR),
985 : TYPE(SQL_C_INTERVAL_DAY_TO_MINUTE),
986 : TYPE(SQL_C_INTERVAL_DAY_TO_SECOND),
987 : TYPE(SQL_C_INTERVAL_HOUR_TO_MINUTE),
988 : TYPE(SQL_C_INTERVAL_HOUR_TO_SECOND),
989 : TYPE(SQL_C_INTERVAL_MINUTE_TO_SECOND),
990 : TYPE(SQL_C_BIT),
991 : TYPE(SQL_C_UBIGINT),
992 : TYPE(SQL_C_TINYINT),
993 : TYPE(SQL_C_SLONG),
994 : TYPE(SQL_C_SSHORT),
995 : TYPE(SQL_C_STINYINT),
996 : TYPE(SQL_C_ULONG),
997 : TYPE(SQL_C_USHORT),
998 : TYPE(SQL_C_UTINYINT),
999 : TYPE(SQL_C_GUID),
1000 : #undef TYPE
1001 : { NULL, 0 }
1002 : };
1003 :
1004 : struct odbc_lookup_int odbc_sql_types[] = {
1005 : #define TYPE(s) { #s, s }
1006 : TYPE(SQL_CHAR),
1007 : TYPE(SQL_VARCHAR),
1008 : TYPE(SQL_LONGVARCHAR),
1009 : TYPE(SQL_WCHAR),
1010 : TYPE(SQL_WVARCHAR),
1011 : TYPE(SQL_WLONGVARCHAR),
1012 : TYPE(SQL_DECIMAL),
1013 : TYPE(SQL_NUMERIC),
1014 : TYPE(SQL_SMALLINT),
1015 : TYPE(SQL_INTEGER),
1016 : TYPE(SQL_REAL),
1017 : TYPE(SQL_FLOAT),
1018 : TYPE(SQL_DOUBLE),
1019 : TYPE(SQL_BIT),
1020 : TYPE(SQL_TINYINT),
1021 : TYPE(SQL_BIGINT),
1022 : TYPE(SQL_BINARY),
1023 : TYPE(SQL_VARBINARY),
1024 : TYPE(SQL_LONGVARBINARY),
1025 : TYPE(SQL_DATE),
1026 : TYPE(SQL_TIME),
1027 : TYPE(SQL_TIMESTAMP),
1028 : TYPE(SQL_TYPE_DATE),
1029 : TYPE(SQL_TYPE_TIME),
1030 : TYPE(SQL_TYPE_TIMESTAMP),
1031 : TYPE(SQL_DATETIME),
1032 : TYPE(SQL_SS_VARIANT),
1033 : TYPE(SQL_SS_UDT),
1034 : TYPE(SQL_SS_XML),
1035 : TYPE(SQL_SS_TABLE),
1036 : TYPE(SQL_SS_TIME2),
1037 : TYPE(SQL_SS_TIMESTAMPOFFSET),
1038 : #ifdef SQL_GUID
1039 : TYPE(SQL_GUID),
1040 : #endif
1041 : #undef TYPE
1042 : { NULL, 0 }
1043 : };
1044 :
1045 : #ifdef _MSC_VER
1046 : /* See https://learn.microsoft.com/en-us/cpp/preprocessor/warning?view=msvc-170 */
1047 : #pragma warning(push)
1048 : #pragma warning(disable:4996)
1049 : #endif
1050 : SQLRETURN
1051 8 : SQLSetStmtOption_nowarning(SQLHSTMT hstmt, SQLSMALLINT option, SQLULEN param)
1052 : {
1053 8 : return SQLSetStmtOption(hstmt, option, param);
1054 : }
1055 : #ifdef _MSC_VER
1056 : #pragma warning(pop)
1057 : #endif
1058 :
1059 : void
1060 866 : odbc_swap_stmts(SQLHSTMT *a, SQLHSTMT *b)
1061 : {
1062 866 : SQLHSTMT tmp = *a;
1063 866 : *a = *b;
1064 866 : *b = tmp;
1065 866 : }
|