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, ¶m_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(¶ms, 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)¶mBatch,
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(¶ms->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(¶ms[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, ¶ms, i, j, num_param_values)) {
2571 /* An input parameter was not of the expected type */
2572 free_params(¶ms, i);
2573 return params;
2574 }
2575 }
2576
2577 Values = retrive_param_values(¶ms[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