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