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