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