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