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, &param_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(&params, 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)&paramBatch,
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(&params->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(&params[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, &params, i, j, num_param_values)) {
2548 		/* An input parameter was not of the expected type */
2549 		free_params(&params, i);
2550 		return params;
2551 	    }
2552 	}
2553 
2554 	Values = retrive_param_values(&params[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