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