1 /*
2 * %CopyrightBegin%
3 *
4 * Copyright Ericsson AB 1999-2016. All Rights Reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * %CopyrightEnd%
19 *
20
21 */
22
23 /*
24 DESCRIPTION: Erlang ODBC (Open Database Connectivity) application. An
25 erlang control process sends request to the c-process that queries the
26 database using the Microsoft ODBC API. The c-process is implemented
27 using two threads the supervisor thread and the database handler thread.
28 If the database thread should hang erlang can close the c-process down
29 by sendig a shutdown request to the supervisor thread.
30
31 Erlang will start this c-process as a port-program and send information
32 regarding inet-port nummbers through the erlang-port.
33 After that c-process will communicate via sockets with erlang. The
34 reason for this is that some odbc-drivers do unexpected things with
35 stdin/stdout messing up the erlang-port communication.
36
37
38 Command protocol between Erlang and C
39 -------------------------------------
40 The requests from Erlang to C are byte lists composed as [CommandByte,
41 Bytes, StringTerminator]
42
43 CommandByte - constants between 0 and 255
44 identifing the request defined in odbc_internal.hrl and odbcserver.h
45
46 Bytes - How to interpret this sequence of bytes depends on the
47 CommandByte.
48
49 StringTerminator - 0
50
51 When the C-program processed the request from erlang it will use the
52 ei-interface to create an Erlang term. This term will be sent the
53 erlang via a socket. The Erlang control process, will forward
54 it to the client that does binary_to_term before returning the result
55 to the client program.
56
57 Here follows a list of [CommandByte, Bytes] that describes the possible
58 values. Note the Bytes part may be empty as in the case
59 of ?CLOSE_CONNECTION and if integer values may be larger than 255
60 they are converted to string values.
61
62 [?OPEN_CONNECTION, C_AutoCommitMode, C_TraceDriver, C_SrollableCursors,
63 C_TupelRow, BinaryStrings, ConnectionStr]
64 [?CLOSE_CONNECTION]
65 [?COMMIT_TRANSACTION, CommitMode]
66 [?QUERY, SQLQuery]
67 [?SELECT_COUNT, SQLQuery]
68 [?SELECT, ?SELECT_FIRST]
69 [?SELECT, ?SELECT_LAST]
70 [?SELECT, ?SELECT_NEXT]
71 [?SELECT, ?SELECT_PREV]
72 [?SELECT, CursorRelation, integer_to_list(OffSet), ";",
73 integer_to_list(N), ";"]
74 [?PARAM_QUERY, Binary]
75
76 C_AutoCommitMode - ?ON | ?OFF
77 C_TraceDriver - ?ON | ?OFF
78 C_SrollableCursors - ?ON | ?OFF
79 C_TupelRow - - ?ON | ?OFF
80 BinaryStrings - ?ON | ?OFF
81 ConnectionStr - String
82 CommitMode - ?COMMIT | ?ROLLBACK
83 SQLQuery - String
84 CursorRelation - ?SELECT_RELATIVE | ?SELECT_ABSOLUTE | ?SELECT_N_NEXT
85 OffSet - integer
86 N - integer
87 Binary - binary encodede tuple of {SQLQuery, NoRows, Parameters}
88 NoRows - integer
89 Parameters - [{Datatype, InOrOut, Value}]
90 InOrOut = [ERL_ODBC_IN | ERL_ODBC_OUT | ERL_ODBC_INOUT]
91 Datatype - USER_INT | USER_SMALL_INT | {USER_DECIMAL, Precision, Scale} |
92 {USER_NMERIC, Precision, Scale} | {USER_CHAR, Max} | {USER_VARCHAR, Max} |
93 {USER_WVARCHAR, Max} | {USER_FLOAT, Precision} | USER_REAL | USER_DOUBLE |
94 USER_TIMESTAMP | {USER_WLONGVARCHAR, Max}
95 Scale - integer
96 Precision - integer
97 Max - integer
98 */
99
100 /* ----------------------------- INCLUDES ------------------------------*/
101
102 #include <ctype.h>
103 #include <stdlib.h>
104 #include <string.h>
105 #include <stdio.h>
106
107 #ifdef UNIX
108 #include <unistd.h>
109 #include <netinet/tcp.h>
110 #endif
111
112 #if defined WIN32
113 #include <winsock2.h>
114 #include <windows.h>
115 #include <ws2tcpip.h >
116 #include <fcntl.h>
117 #include <sql.h>
118 #include <sqlext.h>
119 #else
120 #include "sql.h"
121 #include "sqlext.h"
122 #include <pthread.h>
123 #include <sys/types.h>
124 #include <sys/socket.h>
125 #include <sys/uio.h>
126 #include <netdb.h>
127 #include <netinet/in.h>
128 #endif
129
130 #include <limits.h>
131
132 #include "ei.h"
133 #include "odbcserver.h"
134
135 /* ---------------- Main functions ---------------------------------------*/
136 static void spawn_sup(const char *port);
137 #ifdef WIN32
138 DWORD WINAPI database_handler(const char *port);
139 #else
140 void database_handler(const char *port);
141 #endif
142 static db_result_msg handle_db_request(byte *reqstring, db_state *state);
143 static void supervise(const char *port);
144 /* ----------------- ODBC functions --------------------------------------*/
145
146 static db_result_msg db_connect(byte *connStrIn, db_state *state);
147 static db_result_msg db_close_connection(db_state *state);
148 static db_result_msg db_end_tran(byte compleationtype, db_state *state);
149 static db_result_msg db_query(byte *sql, db_state *state);
150 static db_result_msg db_select_count(byte *sql,db_state *state);
151 static db_result_msg db_select(byte *args, db_state *state);
152 static db_result_msg db_param_query(byte *buffer, db_state *state);
153 static db_result_msg db_describe_table(byte *sql, db_state *state);
154
155 /* ------------- Encode/decode functions -------- ------------------------*/
156
157 static db_result_msg encode_empty_message(void);
158 static db_result_msg encode_error_message(char *reason, char *errCode, SQLINTEGER nativeError);
159 static db_result_msg encode_atom_message(char *atom);
160 static db_result_msg encode_result(db_state *state);
161 static db_result_msg encode_result_set(SQLSMALLINT num_of_columns,
162 db_state *state);
163 static db_result_msg encode_out_params(db_state *state,
164 int cols,
165 param_array *params,
166 int num_param_values);
167 static db_result_msg encode_column_name_list(SQLSMALLINT num_of_columns,
168 db_state *state);
169 static db_result_msg encode_value_list(SQLSMALLINT num_of_columns,
170 db_state *state);
171 static db_result_msg encode_value_list_scroll(SQLSMALLINT num_of_columns,
172 SQLSMALLINT Orientation,
173 SQLINTEGER OffSet, int N,
174 db_state *state);
175 static db_result_msg encode_row_count(SQLINTEGER num_of_rows,
176 db_state *state);
177 static void encode_column_dyn(db_column column, int column_nr,
178 db_state *state);
179 static void encode_data_type(SQLSMALLINT sql_type, SQLINTEGER size,
180 SQLSMALLINT decimal_digits, db_state *state);
181 static Boolean decode_params(db_state *state, byte *buffer, int *index, param_array **params,
182 int i, int j, int num_param_values);
183
184 /*------------- Erlang port communication functions ----------------------*/
185
186 static int read_exact(byte *buf, int len);
187 static byte * receive_erlang_port_msg(void);
188
189 /* ------------- Socket communication functions --------------------------*/
190
191 #ifdef WIN32
192 static SOCKET connect_to_erlang(const char *port);
193 static void send_msg(db_result_msg *msg, SOCKET socket);
194 static byte *receive_msg(SOCKET socket);
195 static Boolean receive_msg_part(SOCKET socket,
196 byte * buffer, size_t msg_len);
197 static Boolean send_msg_part(SOCKET socket, byte * buffer, size_t msg_len);
198 static void close_socket(SOCKET socket);
199 static void init_winsock(void);
200 #elif defined(UNIX)
201 static int connect_to_erlang(const char *port);
202 static void send_msg(db_result_msg *msg, int socket);
203 static byte *receive_msg(int socket);
204 static Boolean receive_msg_part(int socket, byte * buffer, size_t msg_len);
205 static Boolean send_msg_part(int socket, byte * buffer, size_t msg_len);
206 static void close_socket(int socket);
207 static void tcp_nodelay(int sock);
208 #endif
209 static void clean_socket_lib(void);
210
211 /*------------- Memory handling funtions --------------------------------*/
212
213 static void * safe_malloc(int size);
214 static void * safe_realloc(void * ptr, int size);
215 static db_column * alloc_column_buffer(int n);
216 static void free_column_buffer(db_column **columns, int n);
217 static void free_params(param_array **params, int cols);
218 static void clean_state(db_state *state);
219 static SQLLEN* alloc_strlen_indptr(int n, int val);
220
221 /* ------------- Init/map/bind/retrive functions -------------------------*/
222
223 static void init_driver(int erl_auto_commit_mode, int erl_trace_driver,
224 db_state *state);
225 static void init_param_column(param_array *params, byte *buffer, int *index,
226 int num_param_values, db_state* state);
227
228 static void init_param_statement(int cols,
229 SQLLEN num_param_values,
230 db_state *state,
231 param_status *status);
232
233 static void map_dec_num_2_c_column(col_type *type, int precision,
234 int scale);
235 static db_result_msg map_sql_2_c_column(db_column* column, db_state *state);
236
237
238 static param_array * bind_parameter_arrays(byte *buffer, int *index,
239 int cols,
240 int num_param_values,
241 db_state *state);
242 static void * retrive_param_values(param_array *Param);
243
244 static db_column retrive_binary_data(db_column column, int column_nr,
245 db_state *state);
246 static db_result_msg retrive_scrollable_cursor_support_info(db_state
247 *state);
248 static int num_out_params(int num_of_params, param_array* params);
249 /* ------------- Error handling functions --------------------------------*/
250
251 static diagnos get_diagnos(SQLSMALLINT handleType, SQLHANDLE handle, Boolean extendedErrors);
252
253 /* ------------- Boolean functions ---------------------------------------*/
254
255 static db_result_msg more_result_sets(db_state *state);
256 static Boolean sql_success(SQLRETURN result);
257 static void str_tolower(char *str, int len);
258
259 /* ----------------------------- CODE ------------------------------------*/
260
261 #if defined(WIN32)
262 # define DO_EXIT(code) do { ExitProcess((code)); exit((code));} while (0)
263 /* exit() called only to avoid a warning */
264 #else
265 # define DO_EXIT(code) exit((code))
266 #endif
267
268 /* ----------------- Main functions --------------------------------------*/
269
main(void)270 int main(void)
271 {
272 byte *msg = NULL;
273 char *temp = NULL, *supervisor_port = NULL, *odbc_port = NULL;
274 size_t length;
275 #ifdef WIN32
276 _setmode(_fileno( stdin), _O_BINARY);
277 #endif
278
279 msg = receive_erlang_port_msg();
280
281 temp = strtok(msg, ";");
282 if (temp == NULL)
283 DO_EXIT(EXIT_STDIN_BODY);
284 length = strlen(temp);
285 supervisor_port = safe_malloc(length + 1);
286 strcpy(supervisor_port, temp);
287
288 temp = strtok(NULL, ";");
289 if (temp == NULL)
290 DO_EXIT(EXIT_STDIN_BODY);
291 length = strlen(temp);
292 odbc_port = safe_malloc(length + 1);
293 strcpy(odbc_port, temp);
294
295 free(msg);
296
297 spawn_sup(supervisor_port);
298 database_handler(odbc_port);
299
300 return 0;
301 }
302
303 #ifdef WIN32
spawn_sup(const char * port)304 static void spawn_sup(const char *port)
305 {
306 DWORD threadId;
307 (HANDLE)_beginthreadex(NULL, 0, supervise, port, 0, &threadId);
308 }
309 #elif defined(UNIX)
spawn_sup(const char * port)310 static void spawn_sup(const char *port)
311 {
312 pthread_t thread;
313 int result;
314
315 result = pthread_create(&thread, NULL,
316 (void *(*)(void *))supervise,
317 (void *)port);
318 if (result != 0)
319 DO_EXIT(EXIT_THREAD);
320 }
321 #endif
322
supervise(const char * port)323 void supervise(const char *port) {
324 byte *msg = NULL;
325 int reason;
326 #ifdef WIN32
327 SOCKET socket;
328 init_winsock();
329 #elif defined(UNIX)
330 int socket;
331 #endif
332
333 socket = connect_to_erlang(port);
334 msg = receive_msg(socket);
335
336 if(msg[0] == SHUTDOWN) {
337 reason = EXIT_SUCCESS;
338 } else {
339 reason = EXIT_FAILURE; /* Should not happen */
340 }
341
342 free(msg);
343 close_socket(socket);
344 clean_socket_lib();
345 DO_EXIT(reason);
346 }
347
348 #ifdef WIN32
database_handler(const char * port)349 DWORD WINAPI database_handler(const char *port)
350 #else
351 void database_handler(const char *port)
352 #endif
353 {
354 db_result_msg msg;
355 byte *request_buffer = NULL;
356 db_state state =
357 {NULL, NULL, NULL, NULL, 0, {NULL, 0, 0},
358 FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE};
359 byte request_id;
360 #ifdef WIN32
361 SOCKET socket;
362 init_winsock();
363 #elif defined(UNIX)
364 int socket;
365 #endif
366
367 socket = connect_to_erlang(port);
368
369 do {
370 request_buffer = receive_msg(socket);
371
372 request_id = request_buffer[0];
373 msg = handle_db_request(request_buffer, &state);
374
375 send_msg(&msg, socket); /* Send answer to erlang */
376
377 if (msg.dyn_alloc) {
378 ei_x_free(&(state.dynamic_buffer));
379 } else {
380 free(msg.buffer);
381 msg.buffer = NULL;
382 }
383
384 free(request_buffer);
385 request_buffer = NULL;
386
387 } while(request_id != CLOSE_CONNECTION);
388
389 shutdown(socket, 2);
390 close_socket(socket);
391 clean_socket_lib();
392 /* Exit will be done by suervisor thread */
393 #ifdef WIN32
394 return (DWORD)0;
395 #endif
396 }
397
398 /* Description: Calls the appropriate function to handle the database
399 request recived from the erlang-process. Returns a message to send back
400 to erlang. */
handle_db_request(byte * reqstring,db_state * state)401 static db_result_msg handle_db_request(byte *reqstring, db_state *state)
402 {
403 byte *args;
404 byte request_id;
405
406 /* First byte is an index that identifies the requested command the
407 rest is the argument string. */
408 request_id = reqstring[0];
409 args = reqstring + sizeof(byte);
410
411 switch(request_id) {
412 case OPEN_CONNECTION:
413 return db_connect(args, state);
414 case CLOSE_CONNECTION:
415 return db_close_connection(state);
416 case COMMIT_TRANSACTION:
417 if(args[0] == COMMIT) {
418 return db_end_tran((byte)SQL_COMMIT, state);
419 } else { /* args[0] == ROLLBACK */
420 return db_end_tran((byte)SQL_ROLLBACK, state);
421 }
422 case QUERY:
423 return db_query(args, state);
424 case SELECT_COUNT:
425 return db_select_count(args, state);
426 case SELECT:
427 return db_select(args, state);
428 case PARAM_QUERY:
429 return db_param_query(args, state);
430 case DESCRIBE:
431 return db_describe_table(args, state);
432 default:
433 DO_EXIT(EXIT_FAILURE); /* Should not happen */
434 }
435 }
436
437 /* ----------------- ODBC-functions ----------------------------------*/
438
439 /* Description: Tries to open a connection to the database using
440 <connStrIn>, returns a message indicating the outcome. */
db_connect(byte * args,db_state * state)441 static db_result_msg db_connect(byte *args, db_state *state)
442 {
443 /*
444 * Danil Onishchenko aka RubberCthulhu, alevandal@gmail.com. 2013.01.09.
445 * It's a fix for Oracle ODBC driver for Linux.
446 * The issue: Oracle ODBC driver for Linux ignores setup autocommit mode
447 * during driver initialization before a connection to database has been
448 * established.
449 * Solution: set autocommit mode after a connection to database has been
450 * established.
451 *
452 * BEGIN
453 */
454 SQLLEN auto_commit_mode;
455 /* END */
456
457 SQLCHAR connStrOut[MAX_CONN_STR_OUT + 1] = {0};
458 SQLRETURN result;
459 SQLSMALLINT stringlength2ptr = 0, connlen;
460 db_result_msg msg;
461 diagnos diagnos;
462 byte *connStrIn;
463 int erl_auto_commit_mode, erl_trace_driver,
464 use_srollable_cursors, tuple_row_state, binary_strings,
465 extended_errors;
466
467 erl_auto_commit_mode = args[0];
468 erl_trace_driver = args[1];
469 use_srollable_cursors = args[2];
470 tuple_row_state = args[3];
471 binary_strings = args[4];
472 extended_errors = args[5];
473 connStrIn = args + 6 * sizeof(byte);
474
475 if(tuple_row_state == ON) {
476 tuple_row(state) = TRUE;
477 } else {
478 tuple_row(state) = FALSE;
479 }
480
481 if(binary_strings == ON) {
482 binary_strings(state) = TRUE;
483 } else {
484 binary_strings(state) = FALSE;
485 }
486
487 if(use_srollable_cursors == ON) {
488 use_srollable_cursors(state) = TRUE;
489 } else {
490 use_srollable_cursors(state) = FALSE;
491 }
492
493 if(extended_errors == ON) {
494 extended_errors(state) = TRUE;
495 } else {
496 extended_errors(state) = FALSE;
497 }
498
499 init_driver(erl_auto_commit_mode, erl_trace_driver, state);
500
501 connlen = (SQLSMALLINT)strlen((const char*)connStrIn);
502 result = SQLDriverConnect(connection_handle(state), NULL,
503 (SQLCHAR *)connStrIn,
504 connlen,
505 connStrOut, (SQLSMALLINT)MAX_CONN_STR_OUT,
506 &stringlength2ptr, SQL_DRIVER_NOPROMPT);
507
508 if (!sql_success(result)) {
509 diagnos = get_diagnos(SQL_HANDLE_DBC, connection_handle(state), extended_errors(state));
510 strcat((char *)diagnos.error_msg,
511 " Connection to database failed.");
512 msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError );
513
514 if(!sql_success(SQLFreeHandle(SQL_HANDLE_DBC,
515 connection_handle(state))))
516 DO_EXIT(EXIT_FREE);
517 if(!sql_success(SQLFreeHandle(SQL_HANDLE_ENV,
518 environment_handle(state))))
519 DO_EXIT(EXIT_FREE);
520
521 return msg;
522 }
523
524 /*
525 * Danil Onishchenko aka RubberCthulhu, alevandal@gmail.com. 2013.01.09.
526 * It's a fix for Oracle ODBC driver for Linux.
527 * The issue: Oracle ODBC driver for Linux ignores setup autocommit mode
528 * during driver initialization before a connection to database has been
529 * established.
530 * Solution: set autocommit mode after a connection to database has been
531 * established.
532 *
533 * BEGIN
534 */
535 if(erl_auto_commit_mode == ON) {
536 auto_commit_mode = SQL_AUTOCOMMIT_ON;
537 } else {
538 auto_commit_mode = SQL_AUTOCOMMIT_OFF;
539 }
540
541 if(!sql_success(SQLSetConnectAttr(connection_handle(state),
542 SQL_ATTR_AUTOCOMMIT,
543 (SQLPOINTER)auto_commit_mode, 0))) {
544 diagnos = get_diagnos(SQL_HANDLE_DBC, connection_handle(state), extended_errors(state));
545 strcat((char *)diagnos.error_msg, " Set autocommit mode failed.");
546
547 msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
548
549 if(!sql_success(SQLFreeHandle(SQL_HANDLE_DBC,
550 connection_handle(state))))
551 DO_EXIT(EXIT_FREE);
552 if(!sql_success(SQLFreeHandle(SQL_HANDLE_ENV,
553 environment_handle(state))))
554 DO_EXIT(EXIT_FREE);
555
556 return msg;
557 }
558 /* END */
559
560 msg = retrive_scrollable_cursor_support_info(state);
561
562 return msg;
563 }
564
565 /* Close the connection to the database. Returns an ok or error message. */
db_close_connection(db_state * state)566 static db_result_msg db_close_connection(db_state *state)
567 {
568 SQLRETURN result;
569 diagnos diagnos;
570
571 if (associated_result_set(state)) {
572 clean_state(state);
573 }
574
575 result = SQLDisconnect(connection_handle(state));
576
577 if (!sql_success(result)) {
578 diagnos = get_diagnos(SQL_HANDLE_DBC, connection_handle(state), extended_errors(state));
579 return encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
580 }
581
582 if(!sql_success(SQLFreeHandle(SQL_HANDLE_DBC,
583 connection_handle(state))))
584 DO_EXIT(EXIT_FREE);
585 if(!sql_success(SQLFreeHandle(SQL_HANDLE_ENV,
586 environment_handle(state))))
587 DO_EXIT(EXIT_FREE);
588
589 return encode_atom_message("ok");
590 }
591
592
593 /* Description: Requests a commit or rollback operation for all active
594 operations on all statements associated with the connection
595 handle <connection_handle(state)>. Returns an ok or error message. */
db_end_tran(byte compleationtype,db_state * state)596 static db_result_msg db_end_tran(byte compleationtype, db_state *state)
597 {
598 SQLRETURN result;
599 diagnos diagnos;
600
601 result = SQLEndTran(SQL_HANDLE_DBC, connection_handle(state),
602 (SQLSMALLINT)compleationtype);
603
604 if (!sql_success(result)) {
605 diagnos = get_diagnos(SQL_HANDLE_DBC, connection_handle(state), extended_errors(state));
606 return encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
607 } else {
608 return encode_atom_message("ok");
609 }
610 }
611
612 /* Description: Executes an sql query and encodes the result set as an
613 erlang term into the message buffer of the returned message-struct. */
db_query(byte * sql,db_state * state)614 static db_result_msg db_query(byte *sql, db_state *state)
615 {
616 SQLRETURN result;
617 db_result_msg msg;
618 diagnos diagnos;
619 byte is_error[6];
620
621 if (associated_result_set(state)) {
622 clean_state(state);
623 }
624 associated_result_set(state) = FALSE;
625
626 msg = encode_empty_message();
627
628 if(!sql_success(SQLAllocHandle(SQL_HANDLE_STMT,
629 connection_handle(state),
630 &statement_handle(state))))
631 DO_EXIT(EXIT_ALLOC);
632
633 result = SQLExecDirect(statement_handle(state), (SQLCHAR *)sql, SQL_NTS);
634
635 /* SQL_SUCCESS_WITH_INFO at this point may indicate an error in user input. */
636 if (result != SQL_SUCCESS && result != SQL_NO_DATA_FOUND) {
637 diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state));
638 if(strcmp((char *)diagnos.sqlState, INFO) == 0) {
639 is_error[0] = 0;
640 strncat((char *)is_error, (char *)diagnos.error_msg,
641 5);
642 str_tolower((char *)&is_error, 5);
643 /* The ODBC error handling could have been more
644 predictable but alas ... we try to make the best of
645 it as we want a nice and clean Erlang API */
646 if((strcmp((char *)is_error, "error") == 0))
647 {
648 msg = encode_error_message((char *)diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
649 clean_state(state);
650 return msg;
651 }
652 } else {
653 msg = encode_error_message((char *)diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
654 clean_state(state);
655 return msg;
656 }
657 }
658
659 ei_x_new_with_version(&dynamic_buffer(state));
660
661 /* OTP-5759, fails when 0 rows deleted */
662 if (result == SQL_NO_DATA_FOUND) {
663 msg = encode_result(state);
664 } else {
665 /* Handle multiple result sets */
666 do {
667 ei_x_encode_list_header(&dynamic_buffer(state), 1);
668 msg = encode_result(state);
669 /* We don't want to continue if an error occured */
670 if (msg.length != 0) {
671 break;
672 }
673 msg = more_result_sets(state);
674 /* We don't want to continue if an error occured */
675 if (msg.length != 0) {
676 break;
677 }
678 } while (exists_more_result_sets(state));
679
680 ei_x_encode_empty_list(&dynamic_buffer(state));
681 }
682
683 clean_state(state);
684
685 if (msg.length != 0) { /* An error has occurred */
686 ei_x_free(&(dynamic_buffer(state)));
687 return msg;
688 } else {
689 msg.buffer = dynamic_buffer(state).buff;
690 msg.length = dynamic_buffer(state).index;
691 msg.dyn_alloc = TRUE;
692 return msg;
693 }
694 }
695
696 /* Description: Executes an sql query. Returns number of rows in the result
697 set. */
db_select_count(byte * sql,db_state * state)698 static db_result_msg db_select_count(byte *sql, db_state *state)
699 {
700 SQLSMALLINT num_of_columns;
701 SQLLEN num_of_rows;
702 diagnos diagnos;
703
704 if (associated_result_set(state)) {
705 clean_state(state);
706 }
707 associated_result_set(state) = TRUE;
708
709 if(!sql_success(SQLAllocHandle(SQL_HANDLE_STMT,
710 connection_handle(state),
711 &statement_handle(state))))
712 DO_EXIT(EXIT_ALLOC);
713
714 if(use_srollable_cursors(state)) {
715 /* This function will fail if the driver does not support scrollable
716 cursors, this is expected and will not cause any damage*/
717 SQLSetStmtAttr(statement_handle(state),
718 (SQLINTEGER)SQL_ATTR_CURSOR_SCROLLABLE,
719 (SQLPOINTER)SQL_SCROLLABLE, (SQLINTEGER)0);
720 }
721
722 if(!sql_success(SQLExecDirect(statement_handle(state), (SQLCHAR *)sql, SQL_NTS))) {
723 diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state));
724 clean_state(state);
725 return encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
726 }
727
728 if(!sql_success(SQLNumResultCols(statement_handle(state),
729 &num_of_columns)))
730 DO_EXIT(EXIT_COLS);
731
732 nr_of_columns(state) = (int)num_of_columns;
733 columns(state) = alloc_column_buffer(nr_of_columns(state));
734
735 if(!sql_success(SQLRowCount(statement_handle(state), &num_of_rows)))
736 DO_EXIT(EXIT_ROWS);
737
738 return encode_row_count(num_of_rows, state);
739 }
740
741 /* Description: Fetches rows from the result set associated with the
742 connection by db_select_count. The method of seletion will be according
743 too <args> */
db_select(byte * args,db_state * state)744 static db_result_msg db_select(byte *args, db_state *state)
745 {
746 db_result_msg msg;
747 SQLSMALLINT num_of_columns;
748 int offset, n, orientation;
749 byte erlOrientation;
750
751 erlOrientation = args[0];
752
753 switch(erlOrientation) {
754 case SELECT_FIRST:
755 orientation = SQL_FETCH_FIRST;
756 offset = DUMMY_OFFSET;
757 n = 1;
758 break;
759 case SELECT_LAST:
760 orientation = SQL_FETCH_LAST;
761 offset = DUMMY_OFFSET;
762 n = 1;
763 break;
764 case SELECT_NEXT:
765 orientation = SQL_FETCH_NEXT;
766 offset = DUMMY_OFFSET;
767 n = 1;
768 break;
769 case SELECT_PREV:
770 orientation = SQL_FETCH_PRIOR;
771 offset = DUMMY_OFFSET;
772 n = 1;
773 break;
774 case SELECT_ABSOLUTE:
775 orientation = SQL_FETCH_ABSOLUTE;
776 offset = atoi(strtok((char *)(args + sizeof(byte)), ";"));
777 n = atoi(strtok(NULL, ";"));
778 break;
779 case SELECT_RELATIVE:
780 orientation = SQL_FETCH_RELATIVE;
781 offset = atoi(strtok((char *)(args + sizeof(byte)), ";"));
782 n = atoi(strtok(NULL, ";"));
783 break;
784 case SELECT_N_NEXT:
785 orientation = SQL_FETCH_NEXT;
786 offset = atoi(strtok((char *)(args + sizeof(byte)), ";"));
787 n = atoi(strtok(NULL, ";"));
788 break;
789 default:
790 DO_EXIT(EXIT_PARAM_ARRAY);
791 }
792
793 msg = encode_empty_message();
794
795 ei_x_new(&dynamic_buffer(state));
796 ei_x_new_with_version(&dynamic_buffer(state));
797 ei_x_encode_tuple_header(&dynamic_buffer(state), 3);
798 ei_x_encode_atom(&dynamic_buffer(state), "selected");
799
800 num_of_columns = nr_of_columns(state);
801 msg = encode_column_name_list(num_of_columns, state);
802 if (msg.length == 0) { /* If no error has occurred */
803 msg = encode_value_list_scroll(num_of_columns,
804 (SQLSMALLINT)orientation,
805 (SQLINTEGER)offset,
806 n, state);
807 }
808
809 if (msg.length != 0) { /* An error has occurred */
810 ei_x_free(&(dynamic_buffer(state)));
811 return msg;
812 } else {
813 msg.buffer = dynamic_buffer(state).buff;
814 msg.length = dynamic_buffer(state).index;
815 msg.dyn_alloc = TRUE;
816 return msg;
817 }
818 }
819
820 /* Description: Handles parameterized queries ex:
821 INSERT INTO FOO VALUES(?, ?) */
db_param_query(byte * buffer,db_state * state)822 static db_result_msg db_param_query(byte *buffer, db_state *state)
823 {
824 byte *sql;
825 db_result_msg msg;
826 SQLLEN num_param_values;
827 int i, ver = 0,
828 erl_type = 0, index = 0, size = 0, cols = 0;
829 long long_num_param_values;
830 param_status param_status;
831 diagnos diagnos;
832 param_array *params;
833 SQLRETURN result;
834
835 if (associated_result_set(state)) {
836 clean_state(state);
837 }
838 associated_result_set(state) = FALSE;
839 param_query(state) = TRUE;
840 out_params(state) = FALSE;
841
842 msg = encode_empty_message();
843
844 ei_decode_version(buffer, &index, &ver);
845
846 ei_decode_tuple_header(buffer, &index, &size);
847
848 ei_get_type(buffer, &index, &erl_type, &size);
849
850 sql = (byte*)safe_malloc((sizeof(byte) * (size + 1)));
851 ei_decode_string(buffer, &index, sql);
852
853 ei_decode_long(buffer, &index, &long_num_param_values);
854
855 num_param_values = (SQLLEN)long_num_param_values;
856 ei_decode_list_header(buffer, &index, &cols);
857
858
859 init_param_statement(cols, num_param_values, state, ¶m_status);
860
861 params = bind_parameter_arrays(buffer, &index, cols,
862 num_param_values, state);
863
864 if(params != NULL) {
865
866 result = SQLExecDirect(statement_handle(state), (SQLCHAR *)sql, SQL_NTS);
867 if (!sql_success(result) || result == SQL_NO_DATA) {
868 diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state));
869 }
870 /* SQL_NO_DATA and SQLSTATE 00000 indicate success for
871 updates/deletes that affect no rows */
872 if(!sql_success(result) &&
873 !(result == SQL_NO_DATA && !strcmp((char *)diagnos.sqlState, INFO))) {
874 msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
875 } else {
876 for (i = 0; i < param_status.params_processed; i++) {
877 switch (param_status.param_status_array[i]) {
878 case SQL_PARAM_SUCCESS:
879 case SQL_PARAM_SUCCESS_WITH_INFO:
880 /* SQL_PARAM_DIAG_UNAVAILABLE is entered when the
881 * driver treats arrays of parameters as a monolithic
882 * unit, so it does not generate this individual
883 * parameter level of error information. */
884 case SQL_PARAM_DIAG_UNAVAILABLE:
885 break;
886 default:
887 diagnos =
888 get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state));
889 msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
890 i = param_status.params_processed;
891 break;
892 }
893 }
894 if(msg.length == 0) {
895 ei_x_new_with_version(&dynamic_buffer(state));
896 if(out_params(state)){
897 msg = encode_out_params(state, cols, params, num_param_values);
898 }else{
899 msg = encode_result(state);
900 }
901 if(msg.length == 0) {
902 msg.buffer = dynamic_buffer(state).buff;
903 msg.length = dynamic_buffer(state).index;
904 msg.dyn_alloc = TRUE;
905 } else { /* Error occurred */
906 ei_x_free(&(dynamic_buffer(state)));
907 }
908 }
909 }
910
911 if(!sql_success(SQLFreeStmt(statement_handle(state),
912 SQL_RESET_PARAMS))) {
913 DO_EXIT(EXIT_FREE);
914 }
915 } else {
916 msg = encode_atom_message("param_badarg");
917 }
918
919 free(sql);
920
921 free_params(¶ms, cols);
922
923 free(param_status.param_status_array);
924
925 if(!sql_success(SQLFreeHandle(SQL_HANDLE_STMT,
926 statement_handle(state)))){
927 DO_EXIT(EXIT_FREE);
928 }
929 statement_handle(state) = NULL;
930 param_query(state) = FALSE;
931 return msg;
932 }
933
934
db_describe_table(byte * sql,db_state * state)935 static db_result_msg db_describe_table(byte *sql, db_state *state)
936 {
937 db_result_msg msg;
938 SQLSMALLINT num_of_columns;
939 SQLCHAR name[MAX_NAME];
940 SQLSMALLINT name_len, sql_type, dec_digits, nullable;
941 SQLULEN size;
942 diagnos diagnos;
943 int i;
944
945 if (associated_result_set(state)) {
946 clean_state(state);
947 }
948 associated_result_set(state) = FALSE;
949
950 msg = encode_empty_message();
951
952 if(!sql_success(SQLAllocHandle(SQL_HANDLE_STMT,
953 connection_handle(state),
954 &statement_handle(state))))
955 DO_EXIT(EXIT_ALLOC);
956
957 if (!sql_success(SQLPrepare(statement_handle(state), (SQLCHAR *)sql, SQL_NTS))){
958 diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state));
959 msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
960 clean_state(state);
961 return msg;
962 }
963
964 if(!sql_success(SQLNumResultCols(statement_handle(state),
965 &num_of_columns))) {
966 diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state));
967 msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
968 clean_state(state);
969 return msg;
970 }
971
972 ei_x_new_with_version(&dynamic_buffer(state));
973 ei_x_encode_tuple_header(&dynamic_buffer(state), 2);
974 ei_x_encode_atom(&dynamic_buffer(state), "ok");
975 ei_x_encode_list_header(&dynamic_buffer(state), num_of_columns);
976
977 for (i = 0; i < num_of_columns; ++i) {
978
979 if(!sql_success(SQLDescribeCol(statement_handle(state),
980 (SQLUSMALLINT)(i+1),
981 name, sizeof(name), &name_len,
982 &sql_type, &size, &dec_digits,
983 &nullable)))
984 DO_EXIT(EXIT_DESC);
985
986 ei_x_encode_tuple_header(&dynamic_buffer(state), 2);
987 ei_x_encode_string_len(&dynamic_buffer(state),
988 (char *)name, name_len);
989 encode_data_type(sql_type, size, dec_digits, state);
990 }
991
992 ei_x_encode_empty_list(&dynamic_buffer(state));
993
994 clean_state(state);
995 msg.buffer = dynamic_buffer(state).buff;
996 msg.length = dynamic_buffer(state).index;
997 msg.dyn_alloc = TRUE;
998 return msg;
999 }
1000
1001
1002 /* ----------------- Encode/decode functions -----------------------------*/
1003
encode_empty_message(void)1004 static db_result_msg encode_empty_message(void)
1005 {
1006 db_result_msg msg;
1007
1008 msg.length = 0;
1009 msg.buffer = NULL;
1010 msg.dyn_alloc = FALSE;
1011
1012 return msg;
1013 }
1014
1015 /* Description: Encode an error-message to send back to erlang*/
encode_error_message(char * reason,char * errCode,SQLINTEGER nativeError)1016 static db_result_msg encode_error_message(char *reason, char *errCode, SQLINTEGER nativeError )
1017 {
1018 int index;
1019 db_result_msg msg;
1020
1021 index = 0;
1022 ei_encode_version(NULL, &index);
1023 ei_encode_tuple_header(NULL, &index, 2);
1024 ei_encode_atom(NULL, &index, "error");
1025 if (errCode)
1026 {
1027 ei_encode_tuple_header(NULL, &index, 3);
1028 ei_encode_string(NULL, &index, errCode);
1029 ei_encode_long(NULL, &index, nativeError);
1030 }
1031 ei_encode_string(NULL, &index, reason);
1032
1033 msg.length = index;
1034 msg.buffer = (byte *)safe_malloc(index);
1035 msg.dyn_alloc = FALSE;
1036
1037 index = 0;
1038 ei_encode_version((char *)msg.buffer, &index);
1039 ei_encode_tuple_header((char *)msg.buffer, &index, 2);
1040 ei_encode_atom((char *)msg.buffer, &index, "error");
1041 if (errCode)
1042 {
1043 ei_encode_tuple_header((char *)msg.buffer, &index, 3);
1044 ei_encode_string((char *)msg.buffer, &index, errCode);
1045 ei_encode_long((char *)msg.buffer, &index, nativeError);
1046 }
1047 ei_encode_string((char *)msg.buffer, &index, reason);
1048
1049 return msg;
1050 }
1051
1052 /* Description: Encode a messge that is a erlang atom */
encode_atom_message(char * atom)1053 static db_result_msg encode_atom_message(char* atom)
1054 {
1055 int index;
1056 db_result_msg msg;
1057
1058 index = 0;
1059 ei_encode_version(NULL, &index);
1060 ei_encode_atom(NULL, &index, atom);
1061
1062 msg.length = index;
1063 msg.buffer = (byte *)safe_malloc(index);
1064 msg.dyn_alloc = FALSE;
1065
1066 index = 0;
1067 ei_encode_version((char *)msg.buffer, &index);
1068 ei_encode_atom((char *)msg.buffer, &index, atom);
1069
1070 return msg;
1071 }
1072
1073
1074 /* Top encode function for db_query that encodes the resulting erlang
1075 term to be returned to the erlang client. */
encode_result(db_state * state)1076 static db_result_msg encode_result(db_state *state)
1077 {
1078 SQLSMALLINT num_of_columns = 0;
1079 SQLLEN RowCountPtr = 0;
1080 SQLINTEGER paramBatch = 0;
1081 db_result_msg msg;
1082 int elements, update, num_of_rows = 0;
1083 char *atom;
1084 diagnos diagnos;
1085
1086 msg = encode_empty_message();
1087
1088 if(!sql_success(SQLNumResultCols(statement_handle(state),
1089 &num_of_columns))) {
1090 diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state));
1091 msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
1092 clean_state(state);
1093 return msg;
1094 }
1095
1096 if (num_of_columns == 0) {
1097 elements = 2;
1098 atom = "updated";
1099 update = TRUE;
1100 } else {
1101 elements = 3;
1102 atom = "selected";
1103 update = FALSE;
1104 }
1105
1106 if(!sql_success(SQLRowCount(statement_handle(state), &RowCountPtr))) {
1107 diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state));
1108 msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
1109 clean_state(state);
1110 return msg;
1111 }
1112
1113 if(param_query(state) && update) {
1114 if(!sql_success(SQLGetInfo(connection_handle(state),
1115 SQL_PARAM_ARRAY_ROW_COUNTS,
1116 (SQLPOINTER)¶mBatch,
1117 sizeof(paramBatch),
1118 NULL))) {
1119 DO_EXIT(EXIT_DRIVER_INFO);
1120 }
1121
1122 if(paramBatch == SQL_PARC_BATCH ) {
1123 /* Individual row counts (one for each parameter set)
1124 are available, sum them up */
1125 do {
1126 num_of_rows = num_of_rows + (int)RowCountPtr;
1127 msg = more_result_sets(state);
1128 /* We don't want to continue if an error occured */
1129 if (msg.length != 0) {
1130 return msg;
1131 }
1132 if(exists_more_result_sets(state)) {
1133 if(!sql_success(SQLRowCount(statement_handle(state),
1134 &RowCountPtr))) {
1135 DO_EXIT(EXIT_ROWS);
1136 }
1137 }
1138 } while (exists_more_result_sets(state));
1139 } else {
1140 /* Row counts are rolled up into one (SQL_PARC_NO_BATCH) */
1141 num_of_rows = (int)RowCountPtr;
1142 }
1143 } else {
1144 num_of_rows = (int)RowCountPtr;
1145 }
1146 ei_x_encode_tuple_header(&dynamic_buffer(state), elements);
1147 ei_x_encode_atom(&dynamic_buffer(state), atom);
1148 if (update) {
1149 if(num_of_rows < 0 ) {
1150 ei_x_encode_atom(&dynamic_buffer(state), "undefined");
1151 } else {
1152 ei_x_encode_long(&dynamic_buffer(state), num_of_rows);
1153 }
1154 } else {
1155 msg = encode_result_set(num_of_columns, state);
1156 }
1157 return msg;
1158 }
1159
encode_out_params(db_state * state,int num_of_params,param_array * params,int num_param_values)1160 static db_result_msg encode_out_params(db_state *state,
1161 int num_of_params,
1162 param_array* params,
1163 int num_param_values)
1164 {
1165 int num_of_columns = 0;
1166 int i = 0;
1167 int j = 0;
1168 param_array column;
1169 db_result_msg msg;
1170 TIMESTAMP_STRUCT* ts;
1171 msg = encode_empty_message();
1172
1173 ei_x_encode_tuple_header(&dynamic_buffer(state), 3);
1174 ei_x_encode_atom(&dynamic_buffer(state), "executed");
1175
1176 num_of_columns = num_out_params(num_of_params, params);
1177 ei_x_encode_long(&dynamic_buffer(state), num_of_columns);
1178
1179 ei_x_encode_list_header(&dynamic_buffer(state), num_param_values);
1180 for(j =0; j < num_param_values; j ++){
1181
1182 if(tuple_row(state)) {
1183 ei_x_encode_tuple_header(&dynamic_buffer(state), num_of_columns);
1184
1185 } else {
1186 ei_x_encode_list_header(&dynamic_buffer(state), num_of_columns);
1187 }
1188
1189 for (i = 0; i< num_of_params; i++) {
1190 if(params[i].input_output_type==SQL_PARAM_INPUT){
1191 continue;
1192 }
1193 column = params[i];
1194 if (column.type.len == 0 ||
1195 column.type.strlen_or_indptr == SQL_NULL_DATA) {
1196 ei_x_encode_atom(&dynamic_buffer(state), "null");
1197 } else {
1198 void* values = retrive_param_values(&column);
1199 switch(column.type.c) {
1200 case SQL_C_TYPE_TIMESTAMP:
1201 ts = (TIMESTAMP_STRUCT*) values;
1202 ei_x_encode_tuple_header(&dynamic_buffer(state), 2);
1203 ei_x_encode_tuple_header(&dynamic_buffer(state), 3);
1204 ei_x_encode_long(&dynamic_buffer(state), (long)(ts->year));
1205 ei_x_encode_long(&dynamic_buffer(state), (long)(ts->month));
1206 ei_x_encode_long(&dynamic_buffer(state), (long)(ts->day));
1207 ei_x_encode_tuple_header(&dynamic_buffer(state), 3);
1208 ei_x_encode_long(&dynamic_buffer(state), (long)(ts->hour));
1209 ei_x_encode_long(&dynamic_buffer(state), (long)(ts->minute));
1210 ei_x_encode_long(&dynamic_buffer(state), (long)(ts->second));
1211 break;
1212 case SQL_C_CHAR:
1213 if binary_strings(state) {
1214 ei_x_encode_binary(&dynamic_buffer(state),
1215 ((char*)values)+j*column.type.len,
1216 (column.type.strlen_or_indptr_array[j]));
1217 }
1218 else {
1219 ei_x_encode_string(&dynamic_buffer(state),
1220 ((char*)values)+j*column.type.len);
1221 }
1222 break;
1223 case SQL_C_WCHAR:
1224 ei_x_encode_binary(&dynamic_buffer(state),
1225 ((char*)values)+j*column.type.len,
1226 (column.type.strlen_or_indptr_array[j]));
1227 break;
1228 case SQL_C_SLONG:
1229 ei_x_encode_long(&dynamic_buffer(state), ((SQLINTEGER*)values)[j]);
1230 break;
1231 case SQL_C_DOUBLE:
1232 ei_x_encode_double(&dynamic_buffer(state),
1233 ((double*)values)[j]);
1234 break;
1235 case SQL_C_BIT:
1236 ei_x_encode_atom(&dynamic_buffer(state),
1237 ((byte*)values)[j]==TRUE?"true":"false");
1238 break;
1239 default:
1240 ei_x_encode_atom(&dynamic_buffer(state), "error");
1241 break;
1242 }
1243 }
1244 }
1245 if(!tuple_row(state)) {
1246 ei_x_encode_empty_list(&dynamic_buffer(state));
1247 }
1248 }
1249 ei_x_encode_empty_list(&dynamic_buffer(state));
1250 return msg;
1251 }
1252
num_out_params(int num_of_params,param_array * params)1253 static int num_out_params(int num_of_params, param_array* params)
1254 {
1255 int ret = 0;
1256 int i = 0;
1257 for(i=0; i < num_of_params; i++){
1258 if(params[i].input_output_type==SQL_PARAM_INPUT_OUTPUT ||
1259 params[i].input_output_type==SQL_PARAM_OUTPUT)
1260 ret++;
1261 }
1262 return ret;
1263 }
1264
1265 /* Description: Encodes the result set into the "ei_x" - dynamic_buffer
1266 held by the state variable */
encode_result_set(SQLSMALLINT num_of_columns,db_state * state)1267 static db_result_msg encode_result_set(SQLSMALLINT num_of_columns,
1268 db_state *state)
1269 {
1270 db_result_msg msg;
1271
1272 columns(state) = alloc_column_buffer(num_of_columns);
1273
1274 msg = encode_column_name_list(num_of_columns, state);
1275 if (msg.length == 0) { /* If no error has occurred */
1276 msg = encode_value_list(num_of_columns, state);
1277 }
1278
1279 free_column_buffer(&(columns(state)), num_of_columns);
1280
1281 return msg;
1282 }
1283
1284 /* Description: Encodes the list of column names into the "ei_x" -
1285 dynamic_buffer held by the state variable */
encode_column_name_list(SQLSMALLINT num_of_columns,db_state * state)1286 static db_result_msg encode_column_name_list(SQLSMALLINT num_of_columns,
1287 db_state *state)
1288 {
1289 int i;
1290 db_result_msg msg;
1291 SQLCHAR name[MAX_NAME];
1292 SQLSMALLINT name_len, sql_type, dec_digits, nullable;
1293 SQLULEN size;
1294
1295 msg = encode_empty_message();
1296
1297 ei_x_encode_list_header(&dynamic_buffer(state), num_of_columns);
1298
1299 for (i = 0; i < num_of_columns; ++i) {
1300
1301 if(!sql_success(SQLDescribeCol(statement_handle(state),
1302 (SQLSMALLINT)(i+1),
1303 name, sizeof(name), &name_len,
1304 &sql_type, &size, &dec_digits,
1305 &nullable)))
1306 DO_EXIT(EXIT_DESC);
1307
1308 if(sql_type == SQL_LONGVARCHAR || sql_type == SQL_LONGVARBINARY || sql_type == SQL_WLONGVARCHAR)
1309 size = MAXCOLSIZE;
1310
1311 (columns(state)[i]).type.decimal_digits = dec_digits;
1312 (columns(state)[i]).type.sql = sql_type;
1313 (columns(state)[i]).type.col_size = size;
1314
1315 msg = map_sql_2_c_column(&columns(state)[i], state);
1316 if (msg.length > 0) {
1317 return msg; /* An error has occurred */
1318 } else {
1319 if (columns(state)[i].type.len > 0) {
1320 columns(state)[i].buffer =
1321 (char *)safe_malloc(columns(state)[i].type.len);
1322
1323 if (columns(state)[i].type.c == SQL_C_BINARY) {
1324 /* retrived later by retrive_binary_data */
1325 } else {
1326 if(!sql_success(
1327 SQLBindCol
1328 (statement_handle(state),
1329 (SQLSMALLINT)(i+1),
1330 columns(state)[i].type.c,
1331 columns(state)[i].buffer,
1332 columns(state)[i].type.len,
1333 &columns(state)[i].type.strlen_or_indptr)))
1334 DO_EXIT(EXIT_BIND);
1335 }
1336 ei_x_encode_string_len(&dynamic_buffer(state),
1337 (char *)name, name_len);
1338 }
1339 else {
1340 columns(state)[i].type.len = 0;
1341 columns(state)[i].buffer = NULL;
1342 }
1343 }
1344 }
1345 ei_x_encode_empty_list(&dynamic_buffer(state));
1346
1347 return msg;
1348 }
1349
1350 /* Description: Encodes the list(s) of row values fetched by SQLFetch into
1351 the "ei_x" - dynamic_buffer held by the state variable */
encode_value_list(SQLSMALLINT num_of_columns,db_state * state)1352 static db_result_msg encode_value_list(SQLSMALLINT num_of_columns,
1353 db_state *state)
1354 {
1355 int i;
1356 SQLRETURN result;
1357 db_result_msg msg;
1358
1359 msg = encode_empty_message();
1360
1361 for (;;) {
1362 /* fetch the next row */
1363 result = SQLFetch(statement_handle(state));
1364
1365 if (result == SQL_NO_DATA) /* Reached end of result set */
1366 {
1367 break;
1368 }
1369
1370 ei_x_encode_list_header(&dynamic_buffer(state), 1);
1371
1372 if(tuple_row(state)) {
1373 ei_x_encode_tuple_header(&dynamic_buffer(state),
1374 num_of_columns);
1375 } else {
1376 ei_x_encode_list_header(&dynamic_buffer(state), num_of_columns);
1377 }
1378
1379 for (i = 0; i < num_of_columns; i++) {
1380 encode_column_dyn(columns(state)[i], i, state);
1381 }
1382
1383 if(!tuple_row(state)) {
1384 ei_x_encode_empty_list(&dynamic_buffer(state));
1385 }
1386 }
1387 ei_x_encode_empty_list(&dynamic_buffer(state));
1388 return msg;
1389 }
1390
1391 /* Description: Encodes the list(s) of row values fetched with
1392 SQLFetchScroll into the "ei_x" - dynamic_buffer held by the state
1393 variable */
encode_value_list_scroll(SQLSMALLINT num_of_columns,SQLSMALLINT Orientation,SQLINTEGER OffSet,int N,db_state * state)1394 static db_result_msg encode_value_list_scroll(SQLSMALLINT num_of_columns,
1395 SQLSMALLINT Orientation,
1396 SQLINTEGER OffSet, int N,
1397 db_state *state)
1398 {
1399 int i, j;
1400 SQLRETURN result;
1401 db_result_msg msg;
1402
1403 msg = encode_empty_message();
1404
1405 for (j = 0; j < N; j++) {
1406 if((j > 0) && (Orientation == SQL_FETCH_ABSOLUTE)) {
1407 OffSet++;
1408 }
1409
1410 if((j == 1) && (Orientation == SQL_FETCH_RELATIVE)) {
1411 OffSet = 1;
1412 }
1413
1414 result = SQLFetchScroll(statement_handle(state), Orientation,
1415 OffSet);
1416
1417 if (result == SQL_NO_DATA) /* Reached end of result set */
1418 {
1419 break;
1420 }
1421 ei_x_encode_list_header(&dynamic_buffer(state), 1);
1422
1423 if(tuple_row(state)) {
1424 ei_x_encode_tuple_header(&dynamic_buffer(state),
1425 num_of_columns);
1426 } else {
1427 ei_x_encode_list_header(&dynamic_buffer(state), num_of_columns);
1428 }
1429 for (i = 0; i < num_of_columns; i++) {
1430 encode_column_dyn(columns(state)[i], i, state);
1431 }
1432 if(!tuple_row(state)) {
1433 ei_x_encode_empty_list(&dynamic_buffer(state));
1434 }
1435 }
1436 ei_x_encode_empty_list(&dynamic_buffer(state));
1437 return msg;
1438 }
1439
1440 /* Encodes row count result for erlang */
encode_row_count(SQLINTEGER num_of_rows,db_state * state)1441 static db_result_msg encode_row_count(SQLINTEGER num_of_rows,
1442 db_state *state)
1443 {
1444 db_result_msg msg;
1445 int index;
1446
1447 index = 0;
1448 ei_encode_version(NULL, &index);
1449 ei_encode_tuple_header(NULL, &index, 2);
1450 ei_encode_atom(NULL, &index, "ok");
1451 if(num_of_rows == -1)
1452 {
1453 ei_encode_atom(NULL, &index, "undefined");
1454 } else {
1455 ei_encode_long(NULL, &index, num_of_rows);
1456 }
1457 msg.length = index;
1458 msg.buffer = (byte *)safe_malloc(index);
1459 msg.dyn_alloc = FALSE;
1460
1461 index = 0;
1462 ei_encode_version((char *)msg.buffer, &index);
1463 ei_encode_tuple_header((char *)msg.buffer, &index, 2);
1464 ei_encode_atom((char *)msg.buffer, &index, "ok");
1465
1466 if(num_of_rows == -1)
1467 {
1468 ei_encode_atom((char *)msg.buffer, &index, "undefined");
1469 } else {
1470 ei_encode_long((char *)msg.buffer, &index, num_of_rows);
1471 }
1472 return msg;
1473 }
1474
1475 /* Description: Encodes the a column value into the "ei_x" - dynamic_buffer
1476 held by the state variable */
encode_column_dyn(db_column column,int column_nr,db_state * state)1477 static void encode_column_dyn(db_column column, int column_nr,
1478 db_state *state)
1479 {
1480 TIMESTAMP_STRUCT* ts;
1481 if (column.type.len == 0 ||
1482 column.type.strlen_or_indptr == SQL_NULL_DATA) {
1483 ei_x_encode_atom(&dynamic_buffer(state), "null");
1484 } else {
1485 switch(column.type.c) {
1486 case SQL_C_TYPE_TIMESTAMP:
1487 ts = (TIMESTAMP_STRUCT*)column.buffer;
1488 ei_x_encode_tuple_header(&dynamic_buffer(state), 2);
1489 ei_x_encode_tuple_header(&dynamic_buffer(state), 3);
1490 ei_x_encode_ulong(&dynamic_buffer(state), ts->year);
1491 ei_x_encode_ulong(&dynamic_buffer(state), ts->month);
1492 ei_x_encode_ulong(&dynamic_buffer(state), ts->day);
1493 ei_x_encode_tuple_header(&dynamic_buffer(state), 3);
1494 ei_x_encode_ulong(&dynamic_buffer(state), ts->hour);
1495 ei_x_encode_ulong(&dynamic_buffer(state), ts->minute);
1496 ei_x_encode_ulong(&dynamic_buffer(state), ts->second);
1497 break;
1498 case SQL_C_CHAR:
1499 if binary_strings(state) {
1500 ei_x_encode_binary(&dynamic_buffer(state),
1501 column.buffer,column.type.strlen_or_indptr);
1502 } else {
1503 ei_x_encode_string(&dynamic_buffer(state), column.buffer);
1504 }
1505 break;
1506 case SQL_C_WCHAR:
1507 ei_x_encode_binary(&dynamic_buffer(state),
1508 column.buffer,column.type.strlen_or_indptr);
1509 break;
1510 case SQL_C_SLONG:
1511 ei_x_encode_long(&dynamic_buffer(state),
1512 *(SQLINTEGER*)column.buffer);
1513 break;
1514 case SQL_C_DOUBLE:
1515 ei_x_encode_double(&dynamic_buffer(state),
1516 *(double*)column.buffer);
1517 break;
1518 case SQL_C_BIT:
1519 ei_x_encode_atom(&dynamic_buffer(state),
1520 column.buffer[0]?"true":"false");
1521 break;
1522 case SQL_C_BINARY:
1523 column = retrive_binary_data(column, column_nr, state);
1524 if binary_strings(state) {
1525 ei_x_encode_binary(&dynamic_buffer(state),
1526 column.buffer,column.type.strlen_or_indptr);
1527 } else {
1528 ei_x_encode_string(&dynamic_buffer(state), (void *)column.buffer);
1529 }
1530 break;
1531 default:
1532 ei_x_encode_atom(&dynamic_buffer(state), "error");
1533 break;
1534 }
1535 }
1536 }
1537
encode_data_type(SQLSMALLINT sql_type,SQLINTEGER size,SQLSMALLINT decimal_digits,db_state * state)1538 static void encode_data_type(SQLSMALLINT sql_type, SQLINTEGER size,
1539 SQLSMALLINT decimal_digits, db_state *state)
1540 {
1541 switch(sql_type) {
1542 case SQL_CHAR:
1543 ei_x_encode_tuple_header(&dynamic_buffer(state), 2);
1544 ei_x_encode_atom(&dynamic_buffer(state), "sql_char");
1545 ei_x_encode_long(&dynamic_buffer(state), size);
1546 break;
1547 case SQL_VARCHAR:
1548 ei_x_encode_tuple_header(&dynamic_buffer(state), 2);
1549 ei_x_encode_atom(&dynamic_buffer(state), "sql_varchar");
1550 ei_x_encode_long(&dynamic_buffer(state), size);
1551 break;
1552 case SQL_WCHAR:
1553 ei_x_encode_tuple_header(&dynamic_buffer(state), 2);
1554 ei_x_encode_atom(&dynamic_buffer(state), "sql_wchar");
1555 ei_x_encode_long(&dynamic_buffer(state), size);
1556 break;
1557 case SQL_WVARCHAR:
1558 ei_x_encode_tuple_header(&dynamic_buffer(state), 2);
1559 ei_x_encode_atom(&dynamic_buffer(state), "sql_wvarchar");
1560 ei_x_encode_long(&dynamic_buffer(state), size);
1561 break;
1562 case SQL_NUMERIC:
1563 ei_x_encode_tuple_header(&dynamic_buffer(state), 3);
1564 ei_x_encode_atom(&dynamic_buffer(state), "sql_numeric");
1565 ei_x_encode_long(&dynamic_buffer(state), size);
1566 ei_x_encode_long(&dynamic_buffer(state), decimal_digits);
1567 break;
1568 case SQL_DECIMAL:
1569 ei_x_encode_tuple_header(&dynamic_buffer(state), 3);
1570 ei_x_encode_atom(&dynamic_buffer(state), "sql_decimal");
1571 ei_x_encode_long(&dynamic_buffer(state), size);
1572 ei_x_encode_long(&dynamic_buffer(state), decimal_digits);
1573 break;
1574 case SQL_INTEGER:
1575 ei_x_encode_atom(&dynamic_buffer(state), "sql_integer");
1576 break;
1577 case SQL_TINYINT:
1578 ei_x_encode_atom(&dynamic_buffer(state), "sql_tinyint");
1579 break;
1580 case SQL_SMALLINT:
1581 ei_x_encode_atom(&dynamic_buffer(state), "sql_smallint");
1582 break;
1583 case SQL_REAL:
1584 ei_x_encode_atom(&dynamic_buffer(state), "sql_real");
1585 break;
1586 case SQL_FLOAT:
1587 ei_x_encode_tuple_header(&dynamic_buffer(state), 2);
1588 ei_x_encode_atom(&dynamic_buffer(state), "sql_float");
1589 ei_x_encode_long(&dynamic_buffer(state), size);
1590 break;
1591 case SQL_DOUBLE:
1592 ei_x_encode_atom(&dynamic_buffer(state), "sql_double");
1593 break;
1594 case SQL_BIT:
1595 ei_x_encode_atom(&dynamic_buffer(state), "sql_bit");
1596 break;
1597 case SQL_TYPE_DATE:
1598 ei_x_encode_atom(&dynamic_buffer(state), "SQL_TYPE_DATE");
1599 break;
1600 case SQL_TYPE_TIME:
1601 ei_x_encode_atom(&dynamic_buffer(state), "SQL_TYPE_TIME");
1602 break;
1603 case SQL_TYPE_TIMESTAMP:
1604 ei_x_encode_atom(&dynamic_buffer(state), "sql_timestamp");
1605 break;
1606 case SQL_BIGINT:
1607 ei_x_encode_atom(&dynamic_buffer(state), "SQL_BIGINT");
1608 break;
1609 case SQL_BINARY:
1610 ei_x_encode_atom(&dynamic_buffer(state), "SQL_BINARY");
1611 break;
1612 case SQL_LONGVARCHAR:
1613 ei_x_encode_atom(&dynamic_buffer(state), "SQL_LONGVARCHAR");
1614 break;
1615 case SQL_WLONGVARCHAR:
1616 ei_x_encode_tuple_header(&dynamic_buffer(state), 2);
1617 ei_x_encode_atom(&dynamic_buffer(state), "sql_wlongvarchar");
1618 ei_x_encode_long(&dynamic_buffer(state), size);
1619 break;
1620 case SQL_VARBINARY:
1621 ei_x_encode_atom(&dynamic_buffer(state), "SQL_VARBINARY");
1622 break;
1623 case SQL_LONGVARBINARY:
1624 ei_x_encode_atom(&dynamic_buffer(state), "SQL_LONGVARBINARY");
1625 break;
1626 case SQL_INTERVAL_MONTH:
1627 ei_x_encode_atom(&dynamic_buffer(state), "SQL_INTERVAL_MONTH");
1628 break;
1629 case SQL_INTERVAL_YEAR:
1630 ei_x_encode_atom(&dynamic_buffer(state), "SQL_INTERVAL_YEAR");
1631 break;
1632 case SQL_INTERVAL_DAY:
1633 ei_x_encode_atom(&dynamic_buffer(state), "SQL_INTERVAL_DAY");
1634 break;
1635 case SQL_INTERVAL_MINUTE:
1636 ei_x_encode_atom(&dynamic_buffer(state), "SQL_INTERVAL_MINUTE");
1637 break;
1638 case SQL_INTERVAL_HOUR_TO_SECOND:
1639 ei_x_encode_atom(&dynamic_buffer(state),
1640 "SQL_INTERVAL_HOUR_TO_SECOND");
1641 break;
1642 case SQL_INTERVAL_MINUTE_TO_SECOND:
1643 ei_x_encode_atom(&dynamic_buffer(state),
1644 "SQL_INTERVAL_MINUTE_TO_SECOND");
1645 break;
1646 case SQL_UNKNOWN_TYPE:
1647 ei_x_encode_atom(&dynamic_buffer(state), "SQL_UNKNOWN_TYPE");
1648 break;
1649 default: /* Will probably never happen */
1650 ei_x_encode_atom(&dynamic_buffer(state), "ODBC_UNSUPPORTED_TYPE");
1651 break;
1652 }
1653 }
1654
decode_params(db_state * state,byte * buffer,int * index,param_array ** params,int i,int j,int num_param_values)1655 static Boolean decode_params(db_state *state, byte *buffer, int *index, param_array **params,
1656 int i, int j, int num_param_values)
1657 {
1658 int erl_type, size;
1659 long bin_size, l64;
1660 long val;
1661 param_array* param;
1662 TIMESTAMP_STRUCT* ts;
1663 char atomarray[MAXATOMLEN+1];
1664
1665 ei_get_type(buffer, index, &erl_type, &size);
1666 param = &(*params)[i];
1667
1668 if(erl_type == ERL_ATOM_EXT) {
1669 ei_decode_atom(buffer, index, atomarray);
1670 if(strncmp(atomarray, "null", 4) == 0 ) {
1671 param->offset += param->type.len;
1672
1673 if(!param->type.strlen_or_indptr_array)
1674 param->type.strlen_or_indptr_array = alloc_strlen_indptr(num_param_values, param->type.len);
1675
1676 param->type.strlen_or_indptr_array[j] = SQL_NULL_DATA;
1677 return TRUE;
1678 }
1679 }
1680
1681 switch (param->type.c) {
1682 case SQL_C_CHAR:
1683 if (binary_strings(state)) {
1684 ei_decode_binary(buffer, index,
1685 &(param->values.string[param->offset]), &bin_size);
1686 param->offset += param->type.len;
1687 } else {
1688 if(erl_type != ERL_STRING_EXT) {
1689 return FALSE;
1690 }
1691 ei_decode_string(buffer, index, &(param->values.string[param->offset]));
1692 param->offset += param->type.len;
1693 }
1694 break;
1695 case SQL_C_WCHAR:
1696 ei_decode_binary(buffer, index, &(param->values.string[param->offset]), &bin_size);
1697 param->offset += param->type.len;
1698 break;
1699 case SQL_C_TYPE_TIMESTAMP:
1700 ts = (TIMESTAMP_STRUCT*) param->values.string;
1701 ei_decode_tuple_header(buffer, index, &size);
1702 ei_decode_long(buffer, index, &val);
1703 ts[j].year = (SQLUSMALLINT)val;
1704 ei_decode_long(buffer, index, &val);
1705 ts[j].month = (SQLUSMALLINT)val;
1706 ei_decode_long(buffer, index, &val);
1707 ts[j].day = (SQLUSMALLINT)val;
1708 ei_decode_long(buffer, index, &val);
1709 ts[j].hour = (SQLUSMALLINT)val;
1710 ei_decode_long(buffer, index, &val);
1711 ts[j].minute = (SQLUSMALLINT)val;
1712 ei_decode_long(buffer, index, &val);
1713 ts[j].second = (SQLUSMALLINT)val;
1714 ts[j].fraction = (SQLINTEGER)0;
1715 break;
1716 case SQL_C_SLONG:
1717 if(!((erl_type == ERL_SMALL_INTEGER_EXT) ||
1718 (erl_type == ERL_INTEGER_EXT) ||
1719 (erl_type == ERL_SMALL_BIG_EXT) ||
1720 (erl_type == ERL_LARGE_BIG_EXT))) {
1721 return FALSE;
1722 }
1723
1724 if(ei_decode_long(buffer, index, &l64)) {
1725 return FALSE;
1726 }
1727
1728 /* For 64-bit platforms we downcast 8-byte long
1729 * to 4-byte SQLINTEGER, checking for overflow */
1730
1731 if(l64>INT_MAX || l64<INT_MIN) {
1732 return FALSE;
1733 }
1734
1735 param->values.integer[j]=(SQLINTEGER)l64;
1736 break;
1737
1738 case SQL_C_DOUBLE:
1739 if((erl_type != ERL_FLOAT_EXT)) {
1740 return FALSE;
1741 }
1742 ei_decode_double(buffer, index, &(param->values.floating[j]));
1743 break;
1744
1745 case SQL_C_BIT:
1746 if((erl_type != ERL_ATOM_EXT)) {
1747 return FALSE;
1748 }
1749 if (strncmp((char*)atomarray,"true",4) == 0)
1750 param->values.bool[j] = TRUE;
1751 else if (strncmp((char*)atomarray,"false",5) == 0)
1752 param->values.bool[j] = FALSE;
1753 else
1754 return -1;
1755 break;
1756 default:
1757 return FALSE;
1758 }
1759
1760 return TRUE;
1761 }
1762
1763 /*------------- Erlang port communication functions ----------------------*/
1764
1765 /* read from stdin */
1766 #ifdef WIN32
read_exact(byte * buffer,int len)1767 static int read_exact(byte *buffer, int len)
1768 {
1769 HANDLE standard_input = GetStdHandle(STD_INPUT_HANDLE);
1770
1771 unsigned read_result;
1772 unsigned sofar = 0;
1773
1774 if (!len) { /* Happens for "empty packages */
1775 return 0;
1776 }
1777 for (;;) {
1778 if (!ReadFile(standard_input, buffer + sofar,
1779 len - sofar, &read_result, NULL)) {
1780 return -1; /* EOF */
1781 }
1782 if (!read_result) {
1783 return -2; /* Interrupted while reading? */
1784 }
1785 sofar += read_result;
1786 if (sofar == len) {
1787 return len;
1788 }
1789 }
1790 }
1791 #elif defined(UNIX)
read_exact(byte * buffer,int len)1792 static int read_exact(byte *buffer, int len) {
1793 int i, got = 0;
1794
1795 do {
1796 if ((i = read(0, buffer + got, len - got)) <= 0)
1797 return(i);
1798 got += i;
1799 } while (got < len);
1800 return len;
1801
1802 }
1803 #endif
1804
1805
length_buffer_to_size(byte length_buffer[LENGTH_INDICATOR_SIZE])1806 static size_t length_buffer_to_size(byte length_buffer[LENGTH_INDICATOR_SIZE])
1807 {
1808 size_t size = 0, i;
1809
1810 for (i = 0; i < LENGTH_INDICATOR_SIZE; ++i) {
1811 size <<= 8;
1812 size |= (unsigned char)length_buffer[i];
1813 }
1814
1815 return size;
1816 }
1817
1818
1819 /* Recieive (read) data from erlang on stdin */
receive_erlang_port_msg(void)1820 static byte * receive_erlang_port_msg(void)
1821 {
1822 size_t len;
1823 byte *buffer;
1824 byte lengthstr[LENGTH_INDICATOR_SIZE];
1825
1826 if(read_exact(lengthstr, LENGTH_INDICATOR_SIZE) !=
1827 LENGTH_INDICATOR_SIZE)
1828 {
1829 DO_EXIT(EXIT_STDIN_HEADER);
1830 }
1831
1832 len = length_buffer_to_size(lengthstr);
1833
1834 if (len <= 0 || len > 1024) {
1835 DO_EXIT(EXIT_STDIN_HEADER);
1836 }
1837
1838 buffer = (byte *)safe_malloc(len);
1839
1840 if (read_exact(buffer, len) <= 0) {
1841 DO_EXIT(EXIT_STDIN_BODY);
1842 }
1843
1844 if (buffer[len-1] != '\0') {
1845 DO_EXIT(EXIT_STDIN_BODY);
1846 }
1847
1848 return buffer;
1849 }
1850
1851 /* ------------- Socket communication functions --------------------------*/
1852
1853 #if defined(WIN32)
connect_to_erlang(const char * port)1854 static SOCKET connect_to_erlang(const char *port)
1855 #elif defined(UNIX)
1856 static int connect_to_erlang(const char *port)
1857 #endif
1858 {
1859 #if defined(WIN32)
1860 SOCKET sock;
1861 #elif defined(UNIX)
1862 int sock;
1863 #endif
1864 struct sockaddr_in sin;
1865
1866 #if defined(HAVE_STRUCT_SOCKADDR_IN6_SIN6_ADDR) && defined(AF_INET6)
1867 struct sockaddr_in6 sin6;
1868
1869 sock = socket(AF_INET6, SOCK_STREAM, 0);
1870
1871 memset(&sin6, 0, sizeof(sin6));
1872 sin6.sin6_port = htons ((unsigned short)atoi(port));
1873 sin6.sin6_family = AF_INET6;
1874 sin6.sin6_addr = in6addr_loopback;
1875
1876 if (connect(sock, (struct sockaddr*)&sin6, sizeof(sin6)) == 0) {
1877 /* Enable TCP_NODELAY to disable Nagel's socket algorithm. (Removes ~40ms delay on Redhat ES 6). */
1878 #ifdef UNIX
1879 tcp_nodelay(sock);
1880 #endif
1881 return sock;
1882 }
1883 close_socket(sock);
1884 #endif
1885 sock = socket(AF_INET, SOCK_STREAM, 0);
1886
1887 memset(&sin, 0, sizeof(sin));
1888 sin.sin_port = htons ((unsigned short)atoi(port));
1889 sin.sin_family = AF_INET;
1890 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1891
1892 if (connect(sock, (struct sockaddr*)&sin, sizeof(sin)) != 0) {
1893 close_socket(sock);
1894 DO_EXIT(EXIT_SOCKET_CONNECT);
1895 }
1896
1897 /* Enable TCP_NODELAY to disable Nagel's socket algorithm. (Removes ~40ms delay on Redhat ES 6). */
1898 #ifdef UNIX
1899 tcp_nodelay(sock);
1900 #endif
1901 return sock;
1902 }
1903
1904 #ifdef UNIX
tcp_nodelay(int sock)1905 static void tcp_nodelay(int sock)
1906 {
1907 int flag = 1;
1908 int result = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
1909 if (result < 0) {
1910 DO_EXIT(EXIT_SOCKET_CONNECT);
1911 }
1912 }
1913 #endif
1914 #ifdef WIN32
close_socket(SOCKET socket)1915 static void close_socket(SOCKET socket)
1916 {
1917 closesocket(socket);
1918 }
1919 #elif defined(UNIX)
close_socket(int socket)1920 static void close_socket(int socket)
1921 {
1922 close(socket);
1923 }
1924 #endif
1925
1926 #ifdef WIN32
receive_msg(SOCKET socket)1927 static byte * receive_msg(SOCKET socket)
1928 #elif defined(UNIX)
1929 static byte * receive_msg(int socket)
1930 #endif
1931 {
1932 byte lengthstr[LENGTH_INDICATOR_SIZE];
1933 size_t msg_len;
1934 byte *buffer = NULL;
1935
1936 if(!receive_msg_part(socket, lengthstr, LENGTH_INDICATOR_SIZE)) {
1937 close_socket(socket);
1938 DO_EXIT(EXIT_SOCKET_RECV_HEADER);
1939 }
1940
1941 msg_len = length_buffer_to_size(lengthstr);
1942
1943 buffer = (byte *)safe_malloc(msg_len);
1944
1945 if(!receive_msg_part(socket, buffer, msg_len)) {
1946 close_socket(socket);
1947 DO_EXIT(EXIT_SOCKET_RECV_BODY);
1948 }
1949
1950 return buffer;
1951 }
1952
1953 #ifdef WIN32
receive_msg_part(SOCKET socket,byte * buffer,size_t msg_len)1954 static Boolean receive_msg_part(SOCKET socket, byte * buffer, size_t msg_len)
1955 #elif defined(UNIX)
1956 static Boolean receive_msg_part(int socket, byte * buffer, size_t msg_len)
1957 #endif
1958 {
1959 int nr_bytes_received = 0;
1960
1961 nr_bytes_received = recv(socket, (void *)buffer, msg_len, 0);
1962
1963 if(nr_bytes_received == msg_len) {
1964 return TRUE;
1965 } else if(nr_bytes_received > 0 && nr_bytes_received < msg_len) {
1966 return receive_msg_part(socket, buffer + nr_bytes_received,
1967 msg_len - nr_bytes_received);
1968 } else if(nr_bytes_received == -1) {
1969 return FALSE;
1970 } else { /* nr_bytes_received > msg_len */
1971 close_socket(socket);
1972 DO_EXIT(EXIT_SOCKET_RECV_MSGSIZE);
1973 }
1974 }
1975
1976 #ifdef WIN32
send_msg(db_result_msg * msg,SOCKET socket)1977 static void send_msg(db_result_msg *msg, SOCKET socket)
1978 #elif defined(UNIX)
1979 static void send_msg(db_result_msg *msg, int socket)
1980 #endif
1981 {
1982 byte lengthstr[LENGTH_INDICATOR_SIZE];
1983 int len;
1984 len = msg ->length;
1985
1986 lengthstr[0] = (len >> 24) & 0x000000FF;
1987 lengthstr[1] = (len >> 16) & 0x000000FF;
1988 lengthstr[2] = (len >> 8) & 0x000000FF;
1989 lengthstr[3] = len & 0x000000FF;
1990
1991 if(!send_msg_part(socket, lengthstr, LENGTH_INDICATOR_SIZE)) {
1992 close_socket(socket);
1993 DO_EXIT(EXIT_SOCKET_SEND_HEADER);
1994 }
1995
1996 if(!send_msg_part(socket, msg->buffer, len)) {
1997 close_socket(socket);
1998 DO_EXIT(EXIT_SOCKET_SEND_BODY);
1999 }
2000 }
2001
2002 #ifdef WIN32
send_msg_part(SOCKET socket,byte * buffer,size_t msg_len)2003 static Boolean send_msg_part(SOCKET socket, byte * buffer, size_t msg_len)
2004 #elif defined(UNIX)
2005 static Boolean send_msg_part(int socket, byte * buffer, size_t msg_len)
2006 #endif
2007 {
2008 int nr_bytes_sent = 0;
2009
2010 nr_bytes_sent = send(socket, (void *)buffer, msg_len, 0);
2011
2012 if(nr_bytes_sent == msg_len) {
2013 return TRUE;
2014 } else if(nr_bytes_sent > 0 && nr_bytes_sent < msg_len) {
2015 return send_msg_part(socket, buffer + nr_bytes_sent,
2016 msg_len - nr_bytes_sent);
2017 } else if(nr_bytes_sent == -1) {
2018 return FALSE;
2019 } else { /* nr_bytes_sent > msg_len */
2020 close_socket(socket);
2021 DO_EXIT(EXIT_SOCKET_SEND_MSGSIZE);
2022 }
2023 }
2024
2025 #ifdef WIN32
init_winsock(void)2026 static void init_winsock(void)
2027 {
2028 WORD wVersionRequested;
2029 WSADATA wsaData;
2030 int err;
2031
2032 wVersionRequested = MAKEWORD( 2, 0 );
2033
2034 err = WSAStartup( wVersionRequested, &wsaData );
2035 if ( err != 0 ) {
2036 DO_EXIT(EXIT_OLD_WINSOCK);
2037 }
2038
2039 if ( LOBYTE( wsaData.wVersion ) != 2 ||
2040 HIBYTE( wsaData.wVersion ) != 0 ) {
2041 clean_socket_lib();
2042 DO_EXIT(EXIT_OLD_WINSOCK);
2043 }
2044 }
2045 #endif
2046
clean_socket_lib(void)2047 static void clean_socket_lib(void)
2048 {
2049 #ifdef WIN32
2050 WSACleanup();
2051 #endif
2052 }
2053
2054
2055 /*------------- Memmory handling funtions -------------------------------*/
safe_malloc(int size)2056 static void *safe_malloc(int size)
2057 {
2058 void *memory;
2059
2060 memory = (void *)malloc(size);
2061 if (memory == NULL)
2062 DO_EXIT(EXIT_ALLOC);
2063
2064 return memory;
2065 }
2066
safe_realloc(void * ptr,int size)2067 static void *safe_realloc(void *ptr, int size)
2068 {
2069 void *memory;
2070
2071 memory = (void *)realloc(ptr, size);
2072
2073 if (memory == NULL)
2074 {
2075 free(ptr);
2076 DO_EXIT(EXIT_ALLOC);
2077 }
2078 return memory;
2079 }
2080
2081 /* Description: Allocate memory for n columns */
alloc_column_buffer(int n)2082 static db_column * alloc_column_buffer(int n)
2083 {
2084 int i;
2085 db_column *columns;
2086
2087 columns = (db_column *)safe_malloc(n * sizeof(db_column));
2088 for(i = 0; i < n; i++)
2089 columns[i].buffer = NULL;
2090
2091 return columns;
2092 }
2093
2094 /* Description: Deallocate memory allocated by alloc_column_buffer */
free_column_buffer(db_column ** columns,int n)2095 static void free_column_buffer(db_column **columns, int n)
2096 {
2097 int i;
2098 if(*columns != NULL) {
2099 for (i = 0; i < n; i++) {
2100 if((*columns)[i].buffer != NULL) {
2101 free((*columns)[i].buffer);
2102 }
2103 }
2104 free(*columns);
2105 *columns = NULL;
2106 }
2107 }
2108
free_params(param_array ** params,int cols)2109 static void free_params(param_array **params, int cols)
2110 {
2111 int i;
2112 if(*params != NULL) {
2113 for (i = 0; i < cols; i++) {
2114 if((*params)[i].type.strlen_or_indptr_array != NULL){
2115 free((*params)[i].type.strlen_or_indptr_array);
2116 }
2117 free(retrive_param_values(&((*params)[i])));
2118 }
2119 free(*params);
2120 *params = NULL;
2121 }
2122 }
2123
2124 /* Description: Frees resources associated with the current statement handle
2125 keeped in the state.*/
clean_state(db_state * state)2126 static void clean_state(db_state *state)
2127 {
2128 if(statement_handle(state) != NULL) {
2129 if(!sql_success(SQLFreeHandle(SQL_HANDLE_STMT,
2130 statement_handle(state)))) {
2131 DO_EXIT(EXIT_FREE);
2132 }
2133 statement_handle(state) = NULL;
2134 }
2135 free_column_buffer(&(columns(state)), nr_of_columns(state));
2136 columns(state) = NULL;
2137 nr_of_columns(state) = 0;
2138 }
2139
2140 /* Allocates and fill with default value StrLen_or_IndPtr array */
alloc_strlen_indptr(int n,int val)2141 static SQLLEN* alloc_strlen_indptr(int n, int val)
2142 {
2143 int i;
2144 SQLLEN* arr = (SQLLEN*)safe_malloc(n * sizeof(SQLLEN));
2145
2146 for( i=0; i < n; ++i )
2147 arr[i] = val;
2148
2149 return arr;
2150 }
2151
2152 /* ------------- Init/map/bind/retrive functions ------------------------*/
2153
2154 /* Prepare the state for a connection */
init_driver(int erl_auto_commit_mode,int erl_trace_driver,db_state * state)2155 static void init_driver(int erl_auto_commit_mode, int erl_trace_driver,
2156 db_state *state)
2157 {
2158
2159 SQLLEN auto_commit_mode, trace_driver;
2160
2161 if(erl_auto_commit_mode == ON) {
2162 auto_commit_mode = SQL_AUTOCOMMIT_ON;
2163 } else {
2164 auto_commit_mode = SQL_AUTOCOMMIT_OFF;
2165 }
2166
2167 if(erl_trace_driver == ON) {
2168 trace_driver = SQL_OPT_TRACE_ON;
2169 } else {
2170 trace_driver = SQL_OPT_TRACE_OFF;
2171 }
2172
2173 if(!sql_success(SQLAllocHandle(SQL_HANDLE_ENV,
2174 SQL_NULL_HANDLE,
2175 &environment_handle(state))))
2176 DO_EXIT(EXIT_ALLOC);
2177 if(!sql_success(SQLSetEnvAttr(environment_handle(state),
2178 SQL_ATTR_ODBC_VERSION,
2179 (SQLPOINTER)SQL_OV_ODBC3, 0)))
2180 DO_EXIT(EXIT_ENV);
2181 if(!sql_success(SQLAllocHandle(SQL_HANDLE_DBC,
2182 environment_handle(state),
2183 &connection_handle(state))))
2184 DO_EXIT(EXIT_ALLOC);
2185 /* By default Erlang handles all timeouts */
2186 if(!sql_success(SQLSetConnectAttr(connection_handle(state),
2187 SQL_ATTR_CONNECTION_TIMEOUT,
2188 (SQLPOINTER)TIME_OUT, 0)))
2189 DO_EXIT(EXIT_CONNECTION);
2190 if(!sql_success(SQLSetConnectAttr(connection_handle(state),
2191 SQL_ATTR_AUTOCOMMIT,
2192 (SQLPOINTER)auto_commit_mode, 0)))
2193 DO_EXIT(EXIT_CONNECTION);
2194 if(!sql_success(SQLSetConnectAttr(connection_handle(state),
2195 SQL_ATTR_TRACE,
2196 (SQLPOINTER)trace_driver, 0)))
2197 DO_EXIT(EXIT_CONNECTION);
2198 }
2199
init_param_column(param_array * params,byte * buffer,int * index,int num_param_values,db_state * state)2200 static void init_param_column(param_array *params, byte *buffer, int *index,
2201 int num_param_values, db_state* state)
2202 {
2203 long user_type, precision, scale, length;
2204 long in_or_out;
2205
2206 ei_decode_long(buffer, index, &user_type);
2207
2208 params->type.strlen_or_indptr = (SQLLEN)NULL;
2209 params->type.strlen_or_indptr_array = NULL;
2210 params->type.decimal_digits = (SQLINTEGER)0;
2211
2212 switch (user_type) {
2213 case USER_SMALL_INT:
2214 params->type.sql = SQL_SMALLINT;
2215 params->type.c = SQL_C_SLONG;
2216 params->type.len = sizeof(SQLINTEGER);
2217 params->type.col_size = COL_SQL_SMALLINT;
2218 params->values.integer =
2219 (SQLINTEGER*)safe_malloc(num_param_values * params->type.len);
2220 break;
2221 case USER_INT:
2222 params->type.sql = SQL_INTEGER;
2223 params->type.c = SQL_C_SLONG;
2224 params->type.len = sizeof(SQLINTEGER);
2225 params->type.col_size = COL_SQL_INTEGER;
2226 params->values.integer =
2227 (SQLINTEGER*)safe_malloc(num_param_values * params->type.len);
2228 break;
2229 case USER_TINY_INT:
2230 params->type.sql = SQL_TINYINT;
2231 params->type.c = SQL_C_SLONG;
2232 params->type.len = sizeof(SQLINTEGER);
2233 params->type.col_size = COL_SQL_TINYINT;
2234 params->values.integer =
2235 (SQLINTEGER*)safe_malloc(num_param_values * params->type.len);
2236 break;
2237 case USER_DECIMAL:
2238 case USER_NMERIC:
2239 if(user_type == USER_NMERIC) {
2240 params->type.sql = SQL_NUMERIC;
2241 } else {
2242 params->type.sql = SQL_DECIMAL;
2243 }
2244 ei_decode_long(buffer, index, &precision);
2245 ei_decode_long(buffer, index, &scale);
2246 map_dec_num_2_c_column(¶ms->type, (int)precision, (int)scale);
2247 if( params->type.c == SQL_C_SLONG) {
2248 params->values.integer =
2249 (SQLINTEGER *)safe_malloc(num_param_values * params->type.len);
2250 } else if( params->type.c == SQL_C_DOUBLE) {
2251 params->values.floating =
2252 (double *)safe_malloc(num_param_values * params->type.len);
2253 } else if(params->type.c == SQL_C_CHAR) {
2254 params->type.strlen_or_indptr_array
2255 = alloc_strlen_indptr(num_param_values, SQL_NTS);
2256 params->values.string =
2257 (byte *)safe_malloc(num_param_values *
2258 sizeof(byte)* params->type.len);
2259 }
2260 break;
2261 case USER_CHAR:
2262 case USER_VARCHAR:
2263 if(user_type == USER_CHAR) {
2264 params->type.sql = SQL_CHAR;
2265 } else {
2266 params->type.sql = SQL_VARCHAR;
2267 }
2268 ei_decode_long(buffer, index, &length);
2269 /* Max string length + string terminator */
2270 params->type.len = length+1;
2271 params->type.c = SQL_C_CHAR;
2272 params->type.col_size = (SQLUINTEGER)length;
2273 params->type.strlen_or_indptr_array
2274 = alloc_strlen_indptr(num_param_values, SQL_NTS);
2275 params->values.string =
2276 (byte *)safe_malloc(num_param_values *
2277 sizeof(byte)* params->type.len);
2278
2279 break;
2280 case USER_WCHAR:
2281 case USER_WVARCHAR:
2282 case USER_WLONGVARCHAR:
2283 switch (user_type) {
2284 case USER_WCHAR:
2285 params->type.sql = SQL_WCHAR; break;
2286 case USER_WVARCHAR:
2287 params->type.sql = SQL_WVARCHAR; break;
2288 default:
2289 params->type.sql = SQL_WLONGVARCHAR; break;
2290 }
2291 ei_decode_long(buffer, index, &length);
2292 /* Max string length + string terminator */
2293 params->type.len = (length+1)*sizeof(SQLWCHAR);
2294 params->type.c = SQL_C_WCHAR;
2295 params->type.col_size = (SQLUINTEGER)length;
2296 params->type.strlen_or_indptr_array
2297 = alloc_strlen_indptr(num_param_values, SQL_NTS);
2298 params->values.string =
2299 (byte *)safe_malloc(num_param_values * sizeof(byte) * params->type.len);
2300
2301 break;
2302 case USER_TIMESTAMP:
2303 params->type.sql = SQL_TYPE_TIMESTAMP;
2304 params->type.len = sizeof(TIMESTAMP_STRUCT);
2305 params->type.c = SQL_C_TYPE_TIMESTAMP;
2306 params->type.col_size = (SQLUINTEGER)COL_SQL_TIMESTAMP;
2307 params->values.string =
2308 (byte *)safe_malloc(num_param_values * params->type.len);
2309 break;
2310 case USER_FLOAT:
2311 params->type.sql = SQL_FLOAT;
2312 params->type.c = SQL_C_DOUBLE;
2313 params->type.len = sizeof(double);
2314 ei_decode_long(buffer, index, &length);
2315 params->type.col_size = (SQLUINTEGER)length;
2316 params->values.floating =
2317 (double *)safe_malloc(num_param_values * params->type.len);
2318 break;
2319 case USER_REAL:
2320 params->type.sql = SQL_REAL;
2321 params->type.c = SQL_C_DOUBLE;
2322 params->type.len = sizeof(double);
2323 params->type.col_size = COL_SQL_REAL;
2324 params->values.floating =
2325 (double *)safe_malloc(num_param_values * params->type.len);
2326 break;
2327 case USER_DOUBLE:
2328 params->type.sql = SQL_DOUBLE;
2329 params->type.c = SQL_C_DOUBLE;
2330 params->type.len = sizeof(double);
2331 params->type.col_size = COL_SQL_DOUBLE;
2332 params->values.floating =
2333 (double *)safe_malloc(num_param_values * params->type.len);
2334 break;
2335 case USER_BOOLEAN:
2336 params->type.sql = SQL_BIT;
2337 params->type.c = SQL_C_BIT;
2338 params->type.len = sizeof(byte);
2339 params->type.col_size = params->type.len;
2340 params->values.bool =
2341 (byte *)safe_malloc(num_param_values * params->type.len);
2342 break;
2343 }
2344 params->offset = 0;
2345
2346 ei_decode_long(buffer, index, &in_or_out);
2347 switch((in_or_out_type)in_or_out){
2348 case(ERL_ODBC_OUT):
2349 out_params(state) = TRUE;
2350 params->input_output_type = SQL_PARAM_OUTPUT; break;
2351 case(ERL_ODBC_INOUT):
2352 out_params(state) = TRUE;
2353 params->input_output_type = SQL_PARAM_INPUT_OUTPUT; break;
2354 case(ERL_ODBC_IN):
2355 default:
2356 params->input_output_type = SQL_PARAM_INPUT; break;
2357 }
2358
2359 }
2360
init_param_statement(int cols,SQLLEN num_param_values,db_state * state,param_status * status)2361 static void init_param_statement(int cols, SQLLEN num_param_values,
2362 db_state *state, param_status *status)
2363 {
2364 int i;
2365
2366 status -> param_status_array =
2367 (SQLUSMALLINT *)safe_malloc(num_param_values * sizeof(SQLUSMALLINT));
2368
2369 for(i=0; i<num_param_values; i++) {
2370 status -> param_status_array[i] = SQL_PARAM_PROCEED;
2371 }
2372
2373 status -> params_processed = 0;
2374
2375 if(!sql_success(SQLAllocHandle(SQL_HANDLE_STMT,
2376 connection_handle(state),
2377 &statement_handle(state)))) {
2378 DO_EXIT(EXIT_ALLOC);
2379 }
2380
2381 if(num_param_values <= 1) return;
2382
2383 if(!sql_success(SQLSetStmtAttr(statement_handle(state),
2384 SQL_ATTR_PARAM_BIND_TYPE,
2385 SQL_PARAM_BIND_BY_COLUMN, 0))) {
2386 DO_EXIT(EXIT_PARAM_ARRAY);
2387 }
2388
2389 /* Note the (SQLLEN *) cast is correct as the API function SQLSetStmtAttr
2390 takes either an interger or a pointer depending on the attribute */
2391 if(!sql_success(SQLSetStmtAttr(statement_handle(state),
2392 SQL_ATTR_PARAMSET_SIZE,
2393 (SQLLEN *)num_param_values,
2394 0))) {
2395 DO_EXIT(EXIT_PARAM_ARRAY);
2396 }
2397
2398 if(!sql_success(SQLSetStmtAttr(statement_handle(state),
2399 SQL_ATTR_PARAM_STATUS_PTR,
2400 (status -> param_status_array), 0))) {
2401 DO_EXIT(EXIT_PARAM_ARRAY);
2402 }
2403
2404 if(!sql_success(SQLSetStmtAttr(statement_handle(state),
2405 SQL_ATTR_PARAMS_PROCESSED_PTR,
2406 &(status -> params_processed), 0))) {
2407 DO_EXIT(EXIT_PARAM_ARRAY);
2408 }
2409 }
2410
map_dec_num_2_c_column(col_type * type,int precision,int scale)2411 static void map_dec_num_2_c_column(col_type *type, int precision, int scale)
2412 {
2413 type -> col_size = (SQLINTEGER)precision;
2414 type -> decimal_digits = (SQLSMALLINT)scale;
2415
2416 if(precision >= 0 && precision <= 4 && scale == 0) {
2417 type->len = sizeof(SQLINTEGER);
2418 type->c = SQL_C_SLONG;
2419 } else if(precision >= 5 && precision <= 9 && scale == 0) {
2420 type->len = sizeof(SQLINTEGER);
2421 type->c = SQL_C_SLONG;
2422 } else if((precision >= 10 && precision <= 15 && scale == 0)
2423 || (precision <= 15 && scale > 0)) {
2424 type->len = sizeof(double);
2425 type->c = SQL_C_DOUBLE;
2426 } else {
2427 type->len = DEC_NUM_LENGTH;
2428 type->c = SQL_C_CHAR;
2429 }
2430 }
2431
2432 /* Description: Transform SQL columntype to C columntype. Returns a dummy
2433 db_result_msg with length 0 on success and an errormessage otherwise.*/
map_sql_2_c_column(db_column * column,db_state * state)2434 static db_result_msg map_sql_2_c_column(db_column* column, db_state *state)
2435 {
2436 db_result_msg msg;
2437
2438 msg = encode_empty_message();
2439
2440 switch(column -> type.sql) {
2441 case SQL_CHAR:
2442 case SQL_VARCHAR:
2443 case SQL_BINARY:
2444 case SQL_LONGVARCHAR:
2445 case SQL_VARBINARY:
2446 case SQL_LONGVARBINARY:
2447 column -> type.len = (column -> type.col_size) +
2448 /* Make place for NULL termination */
2449 sizeof(byte);
2450 column -> type.c = SQL_C_CHAR;
2451 column -> type.strlen_or_indptr = SQL_NTS;
2452 break;
2453 case SQL_WCHAR:
2454 case SQL_WVARCHAR:
2455 case SQL_WLONGVARCHAR:
2456 column -> type.len = (column -> type.col_size + 1)*sizeof(SQLWCHAR);
2457 column -> type.c = SQL_C_WCHAR;
2458 column -> type.strlen_or_indptr = SQL_NTS;
2459 break;
2460 case SQL_NUMERIC:
2461 case SQL_DECIMAL:
2462 map_dec_num_2_c_column(&(column -> type), column -> type.col_size,
2463 column -> type.decimal_digits);
2464 column -> type.strlen_or_indptr = (SQLLEN)NULL;
2465 break;
2466 case SQL_TINYINT:
2467 case SQL_INTEGER:
2468 case SQL_SMALLINT:
2469 column -> type.len = sizeof(SQLINTEGER);
2470 column -> type.c = SQL_C_SLONG;
2471 column -> type.strlen_or_indptr = (SQLLEN)NULL;
2472 break;
2473 case SQL_REAL:
2474 case SQL_FLOAT:
2475 case SQL_DOUBLE:
2476 column -> type.len = sizeof(double);
2477 column -> type.c = SQL_C_DOUBLE;
2478 column -> type.strlen_or_indptr = (SQLLEN)NULL;
2479 break;
2480 case SQL_TYPE_DATE:
2481 case SQL_TYPE_TIME:
2482 column -> type.len = (column -> type.col_size) +
2483 sizeof(byte);
2484 column -> type.c = SQL_C_CHAR;
2485 column -> type.strlen_or_indptr = SQL_NTS;
2486 break;
2487 case SQL_TYPE_TIMESTAMP:
2488 column -> type.len = sizeof(TIMESTAMP_STRUCT);
2489 column -> type.c = SQL_C_TYPE_TIMESTAMP;
2490 column -> type.strlen_or_indptr = (SQLLEN)NULL;
2491 break;
2492 case SQL_BIGINT:
2493 column -> type.len = DEC_NUM_LENGTH;
2494 column -> type.c = SQL_C_CHAR;
2495 column -> type.strlen_or_indptr = (SQLLEN)NULL;
2496 break;
2497 case SQL_BIT:
2498 column -> type.len = sizeof(byte);
2499 column -> type.c = SQL_C_BIT;
2500 column -> type.strlen_or_indptr = (SQLLEN)NULL;
2501 break;
2502 case SQL_UNKNOWN_TYPE:
2503 msg = encode_error_message("Unknown column type", extended_error(state, ""), 0);
2504 break;
2505 default:
2506 msg = encode_error_message("Column type not supported", extended_error(state, ""), 0);
2507 break;
2508 }
2509 return msg;
2510 }
2511
bind_parameter_arrays(byte * buffer,int * index,int cols,int num_param_values,db_state * state)2512 static param_array * bind_parameter_arrays(byte *buffer, int *index,
2513 int cols, int num_param_values,
2514 db_state *state)
2515 {
2516 int i, j, size, erl_type;
2517 long dummy;
2518 void *Values;
2519 param_array *params;
2520
2521 params = (param_array *)safe_malloc(cols * sizeof(param_array));
2522
2523 for (i = 0; i < cols; i++) {
2524
2525 ei_get_type(buffer, index, &erl_type, &size);
2526
2527 if(erl_type == ERL_NIL_EXT) {
2528 /* End of previous list of column values when i > 0 */
2529 ei_decode_list_header(buffer, index, &size);
2530 }
2531
2532 ei_decode_tuple_header(buffer, index, &size);
2533
2534 init_param_column(¶ms[i], buffer, index, num_param_values, state);
2535
2536 ei_decode_list_header(buffer, index, &size);
2537
2538 if(params[i].type.c == SQL_C_SLONG) {
2539 /* Get rid of the dummy value 256 that is added as the first value
2540 of all integer parameter value lists. This is to avoid that the
2541 list will be encoded as a string if all values are less
2542 than 256 */
2543 ei_decode_long(buffer, index, &dummy);
2544 }
2545
2546 for (j = 0; j < num_param_values; j++) {
2547 if(!decode_params(state, buffer, index, ¶ms, i, j, num_param_values)) {
2548 /* An input parameter was not of the expected type */
2549 free_params(¶ms, i);
2550 return params;
2551 }
2552 }
2553
2554 Values = retrive_param_values(¶ms[i]);
2555
2556 if(!sql_success(
2557 SQLBindParameter(statement_handle(state), i + 1,
2558 params[i].input_output_type,
2559 params[i].type.c,
2560 params[i].type.sql,
2561 params[i].type.col_size,
2562 params[i].type.decimal_digits, Values,
2563 params[i].type.len,
2564 params[i].type.strlen_or_indptr_array))) {
2565 DO_EXIT(EXIT_BIND);
2566 }
2567 }
2568
2569 return params;
2570 }
2571
retrive_param_values(param_array * Param)2572 static void * retrive_param_values(param_array *Param)
2573 {
2574 switch(Param->type.c) {
2575 case SQL_C_CHAR:
2576 case SQL_C_WCHAR:
2577 case SQL_C_TYPE_TIMESTAMP:
2578 return (void *)Param->values.string;
2579 case SQL_C_SLONG:
2580 return (void *)Param->values.integer;
2581 case SQL_C_DOUBLE:
2582 return (void *)Param->values.floating;
2583 case SQL_C_BIT:
2584 return (void *)Param->values.bool;
2585 default:
2586 DO_EXIT(EXIT_FAILURE); /* Should not happen */
2587 }
2588 }
2589
2590 /* Description: More than one call to SQLGetData may be required to retrieve
2591 data from a single column with binary data. SQLGetData then returns
2592 SQL_SUCCESS_WITH_INFO nd the SQLSTATE will have the value 01004 (Data
2593 truncated). The application can then use the same column number to
2594 retrieve subsequent parts of the data until SQLGetData returns
2595 SQL_SUCCESS, indicating that all data for the column has been retrieved.
2596 */
2597
retrive_binary_data(db_column column,int column_nr,db_state * state)2598 static db_column retrive_binary_data(db_column column, int column_nr,
2599 db_state *state)
2600 {
2601 char *outputptr;
2602 int blocklen, outputlen, result;
2603 diagnos diagnos;
2604
2605 blocklen = column.type.len;
2606 outputptr = column.buffer;
2607 result = SQLGetData(statement_handle(state), (SQLSMALLINT)(column_nr+1),
2608 SQL_C_CHAR, outputptr,
2609 blocklen, &column.type.strlen_or_indptr);
2610
2611 while (result == SQL_SUCCESS_WITH_INFO) {
2612
2613 diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state));
2614
2615 if(strcmp((char *)diagnos.sqlState, TRUNCATED) == 0) {
2616 outputlen = column.type.len - 1;
2617 column.type.len = outputlen + blocklen;
2618 column.buffer =
2619 safe_realloc((void *)column.buffer, column.type.len);
2620 outputptr = column.buffer + outputlen;
2621 result = SQLGetData(statement_handle(state),
2622 (SQLSMALLINT)(column_nr+1), SQL_C_CHAR,
2623 outputptr, blocklen,
2624 &column.type.strlen_or_indptr);
2625 }
2626 }
2627
2628 if (result == SQL_SUCCESS) {
2629 return column;
2630 } else {
2631 DO_EXIT(EXIT_BIN);
2632 }
2633 }
2634
2635 /* Description: Returns information about support for scrollable cursors */
retrive_scrollable_cursor_support_info(db_state * state)2636 static db_result_msg retrive_scrollable_cursor_support_info(db_state *state)
2637 {
2638 db_result_msg msg;
2639 SQLUINTEGER supportMask;
2640
2641 ei_x_new_with_version(&dynamic_buffer(state));
2642 ei_x_encode_tuple_header(&dynamic_buffer(state), 3);
2643 ei_x_encode_atom(&dynamic_buffer(state), "ok");
2644
2645 if(use_srollable_cursors(state)) {
2646
2647 if(!sql_success(SQLGetInfo(connection_handle(state),
2648 SQL_DYNAMIC_CURSOR_ATTRIBUTES1,
2649 (SQLPOINTER)&supportMask,
2650 sizeof(supportMask),
2651 NULL))) {
2652 DO_EXIT(EXIT_DRIVER_INFO);
2653 }
2654
2655 if ((supportMask & SQL_CA1_ABSOLUTE)) {
2656 ei_x_encode_atom(&dynamic_buffer(state), "true");
2657 }
2658 else {
2659 ei_x_encode_atom(&dynamic_buffer(state), "false");
2660 }
2661
2662 if ((supportMask & SQL_CA1_RELATIVE)) {
2663 ei_x_encode_atom(&dynamic_buffer(state), "true");
2664 }
2665 else {
2666 ei_x_encode_atom(&dynamic_buffer(state), "false");
2667 }
2668 } else { /* Scrollable cursors disabled by the user */
2669 ei_x_encode_atom(&dynamic_buffer(state), "false");
2670 ei_x_encode_atom(&dynamic_buffer(state), "false");
2671 }
2672 msg.buffer = dynamic_buffer(state).buff;
2673 msg.length = dynamic_buffer(state).index;
2674 msg.dyn_alloc = TRUE;
2675 return msg;
2676 }
2677
2678 /* ------------- Boolean functions ---------------------------------------*/
2679
2680 /* Check if there are any more result sets */
more_result_sets(db_state * state)2681 static db_result_msg more_result_sets(db_state *state)
2682 {
2683 SQLRETURN result;
2684 diagnos diagnos;
2685 db_result_msg msg;
2686
2687 msg = encode_empty_message();
2688 result = SQLMoreResults(statement_handle(state));
2689
2690 if(sql_success(result)){
2691 exists_more_result_sets(state) = TRUE;
2692 return msg;
2693 } else if(result == SQL_NO_DATA) {
2694 exists_more_result_sets(state) = FALSE;
2695 return msg;
2696 } else {
2697 /* As we found an error we do not care about any potential more result
2698 sets */
2699 exists_more_result_sets(state) = FALSE;
2700 diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state));
2701 strcat((char *)diagnos.error_msg,
2702 "Failed to create on of the result sets");
2703 msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
2704 return msg;
2705 }
2706 }
2707
sql_success(SQLRETURN result)2708 static Boolean sql_success(SQLRETURN result)
2709 {
2710 return result == SQL_SUCCESS || result == SQL_SUCCESS_WITH_INFO;
2711 }
2712
2713 /* ------------- Error handling functions --------------------------------*/
2714
2715 /* Description: An ODBC function can post zero or more diagnostic records
2716 each time it is called. This function loops through the current set of
2717 diagnostic records scaning for error messages and the sqlstate.
2718 If this function is called when no error has ocurred only the sqlState
2719 field may be referenced.*/
get_diagnos(SQLSMALLINT handleType,SQLHANDLE handle,Boolean extendedErrors)2720 static diagnos get_diagnos(SQLSMALLINT handleType, SQLHANDLE handle, Boolean extendedErrors)
2721 {
2722 diagnos diagnos;
2723 SQLINTEGER nativeError;
2724 SQLSMALLINT errmsg_buffer_size, record_nr, errmsg_size;
2725 int acc_errmsg_size;
2726 byte *current_errmsg_pos;
2727 SQLCHAR current_sql_state[SQL_STATE_SIZE];
2728 SQLRETURN result;
2729
2730 diagnos.error_msg[0] = 0;
2731
2732 current_errmsg_pos = (byte *)diagnos.error_msg;
2733
2734 /* number bytes free in error message buffer */
2735 errmsg_buffer_size = MAX_ERR_MSG - ERRMSG_HEADR_SIZE;
2736 acc_errmsg_size = 0; /* number bytes used in the error message buffer */
2737
2738 /* Foreach diagnostic record in the current set of diagnostic records
2739 the error message is obtained */
2740 for(record_nr = 1; ;record_nr++) {
2741 result = SQLGetDiagRec(handleType, handle, record_nr, current_sql_state,
2742 &nativeError, (SQLCHAR *)current_errmsg_pos,
2743 (SQLSMALLINT)errmsg_buffer_size, &errmsg_size);
2744 if(result == SQL_SUCCESS) {
2745 /* update the sqlstate in the diagnos record, because the SQLGetDiagRec
2746 call succeeded */
2747 memcpy(diagnos.sqlState, current_sql_state, SQL_STATE_SIZE);
2748 diagnos.nativeError = nativeError;
2749 errmsg_buffer_size = errmsg_buffer_size - errmsg_size;
2750 acc_errmsg_size = acc_errmsg_size + errmsg_size;
2751 current_errmsg_pos = current_errmsg_pos + errmsg_size;
2752 } else if(result == SQL_SUCCESS_WITH_INFO && errmsg_size >= errmsg_buffer_size) {
2753 memcpy(diagnos.sqlState, current_sql_state, SQL_STATE_SIZE);
2754 diagnos.nativeError = nativeError;
2755 acc_errmsg_size = errmsg_buffer_size;
2756 break;
2757 } else {
2758 break;
2759 }
2760 }
2761
2762 if(acc_errmsg_size == 0) {
2763 strcat((char *)diagnos.error_msg,
2764 "No SQL-driver information available.");
2765 }
2766 else if (!extendedErrors){
2767 strcat(strcat((char *)diagnos.error_msg, " SQLSTATE IS: "),
2768 (char *)diagnos.sqlState);
2769 }
2770 return diagnos;
2771 }
2772
str_tolower(char * str,int len)2773 static void str_tolower(char *str, int len)
2774 {
2775 int i;
2776
2777 for(i = 0; i <= len; i++) {
2778 str[i] = tolower(str[i]);
2779 }
2780 }
2781