2 * sql_sybase.c Sybase (ctlibrary) routines for rlm_sql
3 * Error handling stolen from Sybase example code "firstapp.c"
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 * Copyright 2000,2006 The FreeRADIUS server project
20 * Copyright 2000 Mattias Sjostrom <mattias@nogui.se>
23 #include <freeradius-devel/ident.h>
26 #include <freeradius-devel/autoconf.h>
33 #include <freeradius-devel/radiusd.h>
39 typedef struct rlm_sql_sybase_sock {
41 CS_CONNECTION *connection;
47 } rlm_sql_sybase_sock;
50 #define MAX_DATASTR_LEN 256
52 /************************************************************************
53 * Handler for server messages. Client-Library will call this
54 * routine when it receives a message from the server.
55 ************************************************************************/
57 static CS_RETCODE CS_PUBLIC
58 servermsg_callback(cp, chp, msgp)
65 ** Print the message info.
68 "Sybase Server message:\n");
70 "number(%ld) severity(%ld) state(%ld) line(%ld)\n",
71 (long)msgp->msgnumber, (long)msgp->severity,
72 (long)msgp->state, (long)msgp->line);
75 ** Print the server and procedure names if supplied.
77 if (msgp->svrnlen > 0 && msgp->proclen > 0)
78 radlog(L_ERR, "Server name: %s Procedure name: %s", msgp->svrname, msgp->proc);
81 ** Print the null terminated message.
83 radlog(L_ERR, "%s\n", msgp->text);
86 ** Server message callbacks must return CS_SUCCEED.
91 /************************************************************************
92 * Client-Library error handler.
93 ************************************************************************/
95 static CS_RETCODE CS_PUBLIC
96 clientmsg_callback(context, conn, emsgp)
103 ** Error number: Print the error's severity, number, origin, and
104 ** layer. These four numbers uniquely identify the error.
107 "Client Library error:\n");
109 "severity(%ld) number(%ld) origin(%ld) layer(%ld)\n",
110 (long)CS_SEVERITY(emsgp->severity),
111 (long)CS_NUMBER(emsgp->msgnumber),
112 (long)CS_ORIGIN(emsgp->msgnumber),
113 (long)CS_LAYER(emsgp->msgnumber));
116 ** Error text: Print the error text.
118 radlog(L_ERR, "%s\n", emsgp->msgstring);
120 if (emsgp->osstringlen > 0)
123 "Operating system error number(%ld):\n",
124 (long)emsgp->osnumber);
125 radlog(L_ERR, "%s\n", emsgp->osstring);
131 /************************************************************************
132 * CS-Library error handler. This function will be invoked
133 * when CS-Library has detected an error.
134 ************************************************************************/
136 static CS_RETCODE CS_PUBLIC
137 csmsg_callback(context, emsgp)
143 ** Print the error number and message.
146 "CS-Library error:\n");
148 "\tseverity(%ld) layer(%ld) origin(%ld) number(%ld)",
149 (long)CS_SEVERITY(emsgp->msgnumber),
150 (long)CS_LAYER(emsgp->msgnumber),
151 (long)CS_ORIGIN(emsgp->msgnumber),
152 (long)CS_NUMBER(emsgp->msgnumber));
154 radlog(L_ERR, "%s\n", emsgp->msgstring);
157 ** Print any operating system error information.
159 if (emsgp->osstringlen > 0)
161 radlog(L_ERR, "Operating System Error: %s\n",
168 /*************************************************************************
170 * Function: sql_init_socket
172 * Purpose: Establish connection to the db
174 *************************************************************************/
175 static int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
177 rlm_sql_sybase_sock *sybase_sock;
180 if (!sqlsocket->conn) {
181 sqlsocket->conn = (rlm_sql_sybase_sock *)rad_malloc(sizeof(rlm_sql_sybase_sock));
182 if (!sqlsocket->conn) {
186 sybase_sock = sqlsocket->conn;
187 memset(sybase_sock, 0, sizeof(*sybase_sock));
189 sybase_sock->results=NULL;
191 /* Allocate a CS context structure. This should really only be done once, but because of
192 the connection pooling design of rlm_sql, we'll have to go with one context per connection */
194 if (cs_ctx_alloc(CS_VERSION_100, &sybase_sock->context) != CS_SUCCEED) {
195 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to allocate CS context structure (cs_ctx_alloc())");
199 /* Initialize ctlib */
201 if (ct_init(sybase_sock->context, CS_VERSION_100) != CS_SUCCEED) {
202 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to initialize Client-Library (ct_init())");
203 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
204 cs_ctx_drop(sybase_sock->context);
209 /* Install callback functions for error-handling */
211 if (cs_config(sybase_sock->context, CS_SET, CS_MESSAGE_CB, (CS_VOID *)csmsg_callback, CS_UNUSED, NULL) != CS_SUCCEED) {
212 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to install CS Library error callback");
213 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
214 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
215 cs_ctx_drop(sybase_sock->context);
220 if (ct_callback(sybase_sock->context, NULL, CS_SET, CS_CLIENTMSG_CB, (CS_VOID *)clientmsg_callback) != CS_SUCCEED) {
221 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to install client message callback");
222 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
223 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
224 cs_ctx_drop(sybase_sock->context);
229 if (ct_callback(sybase_sock->context, NULL, CS_SET, CS_SERVERMSG_CB, (CS_VOID *)servermsg_callback) != CS_SUCCEED) {
230 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to install client message callback");
231 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
232 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
233 cs_ctx_drop(sybase_sock->context);
238 /* Allocate a ctlib connection structure */
240 if (ct_con_alloc(sybase_sock->context, &sybase_sock->connection) != CS_SUCCEED) {
241 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to allocate connection structure (ct_con_alloc())");
242 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
243 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
244 cs_ctx_drop(sybase_sock->context);
249 /* Initialize inline error handling for the connection */
251 /* if (ct_diag(sybase_sock->connection, CS_INIT, CS_UNUSED, CS_UNUSED, NULL) != CS_SUCCEED) {
252 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to initialize error handling (ct_diag())");
253 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
254 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
255 cs_ctx_drop(sybase_sock->context);
262 /* Set User and Password properties for the connection */
264 if (ct_con_props(sybase_sock->connection, CS_SET, CS_USERNAME, config->sql_login,
265 strlen(config->sql_login), NULL) != CS_SUCCEED) {
266 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to set username for connection (ct_con_props())\n%s",
267 sql_error(sqlsocket, config));
268 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
269 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
270 cs_ctx_drop(sybase_sock->context);
275 if (ct_con_props(sybase_sock->connection, CS_SET, CS_PASSWORD, config->sql_password,
276 strlen(config->sql_password), NULL) != CS_SUCCEED) {
277 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to set password for connection (ct_con_props())\n%s",
278 sql_error(sqlsocket, config));
279 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
280 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
281 cs_ctx_drop(sybase_sock->context);
286 /* Establish the connection */
288 if (ct_connect(sybase_sock->connection, config->sql_server, strlen(config->sql_server)) != CS_SUCCEED) {
289 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to establish connection to symbolic servername %s\n%s",
290 config->sql_server, sql_error(sqlsocket, config));
291 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
292 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
293 cs_ctx_drop(sybase_sock->context);
301 /*************************************************************************
303 * Function: sql_destroy_socket
305 * Purpose: Free socket and private connection data
307 *************************************************************************/
308 static int sql_destroy_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config)
310 free(sqlsocket->conn);
311 sqlsocket->conn = NULL;
315 /*************************************************************************
317 * Function: sql_query
319 * Purpose: Issue a non-SELECT query (ie: update/delete/insert) to
322 *************************************************************************/
323 static int sql_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
325 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
327 CS_RETCODE ret, results_ret;
330 if (config->sqltrace)
332 if (sybase_sock->connection == NULL) {
333 radlog(L_ERR, "Socket not connected");
337 if (ct_cmd_alloc(sybase_sock->connection, &sybase_sock->command) != CS_SUCCEED) {
338 radlog(L_ERR,"rlm_sql_sybase(sql_query): Unable to allocate command structure (ct_cmd_alloc())\n%s",
339 sql_error(sqlsocket, config));
343 if (ct_command(sybase_sock->command, CS_LANG_CMD, querystr, CS_NULLTERM, CS_UNUSED) != CS_SUCCEED) {
344 radlog(L_ERR,"rlm_sql_sybase(sql_query): Unable to initiate command structure (ct_command())\n%s",
345 sql_error(sqlsocket, config));
349 if (ct_send(sybase_sock->command) != CS_SUCCEED) {
350 radlog(L_ERR,"rlm_sql_sybase(sql_query): Unable to send command (ct_send())\n%s",
351 sql_error(sqlsocket, config));
356 ** We'll make three calls to ct_results, first to get a success indicator, secondly to get a done indicator, and
357 ** thirdly to get a "nothing left to handle" status.
361 ** First call to ct_results,
362 ** we need returncode CS_SUCCEED
363 ** and result_type CS_CMD_SUCCEED.
366 if ((results_ret = ct_results(sybase_sock->command, &result_type)) == CS_SUCCEED) {
367 if (result_type != CS_CMD_SUCCEED) {
368 if (result_type == CS_ROW_RESULT) {
369 radlog(L_ERR,"rlm_sql_sybase(sql_query): sql_query processed a query returning rows. Use sql_select_query instead!");
371 radlog(L_ERR,"rlm_sql_sybase(sql_query): Result failure or unexpected result type from query\n%s",
372 sql_error(sqlsocket, config));
377 switch ((int) results_ret)
380 case CS_FAIL: /* Serious failure, sybase requires us to cancel and maybe even close connection */
381 radlog(L_ERR,"rlm_sql_sybase(sql_query): Failure retrieving query results\n%s"
382 , sql_error(sqlsocket, config));
383 if ((ret = ct_cancel(NULL, sybase_sock->command, CS_CANCEL_ALL)) == CS_FAIL) {
384 radlog(L_ERR,"rlm_sql_sybase(sql_query): cleaning up.");
385 ct_close(sybase_sock->connection, CS_FORCE_CLOSE);
386 sql_close(sqlsocket, config);
392 radlog(L_ERR,"rlm_sql_sybase(sql_query): Unexpected return value from ct_results()\n%s",
393 sql_error(sqlsocket, config));
400 ** Second call to ct_results,
401 ** we need returncode CS_SUCCEED
402 ** and result_type CS_CMD_DONE.
405 if ((results_ret = ct_results(sybase_sock->command, &result_type)) == CS_SUCCEED) {
406 if (result_type != CS_CMD_DONE) {
407 radlog(L_ERR,"rlm_sql_sybase(sql_query): Result failure or unexpected result type from query\n%s",
408 sql_error(sqlsocket, config));
413 switch ((int) results_ret)
416 case CS_FAIL: /* Serious failure, sybase requires us to cancel and maybe even close connection */
417 radlog(L_ERR,"rlm_sql_sybase(sql_query): Failure retrieving query results\n%s"
418 , sql_error(sqlsocket, config));
419 if ((ret = ct_cancel(NULL, sybase_sock->command, CS_CANCEL_ALL)) == CS_FAIL) {
420 radlog(L_ERR,"rlm_sql_sybase(sql_query): cleaning up.");
421 ct_close(sybase_sock->connection, CS_FORCE_CLOSE);
422 sql_close(sqlsocket, config);
428 radlog(L_ERR,"rlm_sql_sybase(sql_query): Unexpected return value from ct_results()\n%s",
429 sql_error(sqlsocket, config));
436 ** Third call to ct_results,
437 ** we need returncode CS_END_RESULTS
438 ** result_type will be ignored.
441 results_ret = ct_results(sybase_sock->command, &result_type);
443 switch ((int) results_ret)
446 case CS_FAIL: /* Serious failure, sybase requires us to cancel and maybe even close connection */
447 radlog(L_ERR,"rlm_sql_sybase(sql_query): Failure retrieving query results\n%s"
448 , sql_error(sqlsocket, config));
449 if ((ret = ct_cancel(NULL, sybase_sock->command, CS_CANCEL_ALL)) == CS_FAIL) {
450 radlog(L_ERR,"rlm_sql_sybase(sql_query): cleaning up.");
451 ct_close(sybase_sock->connection, CS_FORCE_CLOSE);
452 sql_close(sqlsocket, config);
457 case CS_END_RESULTS: /* This is where we want to end up */
461 radlog(L_ERR,"rlm_sql_sybase(sql_query): Unexpected return value from ct_results()\n%s",
462 sql_error(sqlsocket, config));
472 /*************************************************************************
474 * Function: sql_select_query
476 * Purpose: Issue a select query to the database
478 * Note: Only the first row from queries returning several rows
479 * will be returned by this function, consequitive rows will
482 *************************************************************************/
483 static int sql_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
485 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
487 CS_RETCODE ret, results_ret;
489 CS_DATAFMT descriptor;
494 if (config->sqltrace)
496 if (sybase_sock->connection == NULL) {
497 radlog(L_ERR, "Socket not connected");
502 if (ct_cmd_alloc(sybase_sock->connection, &sybase_sock->command) != CS_SUCCEED) {
503 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Unable to allocate command structure (ct_cmd_alloc())\n%s",
504 sql_error(sqlsocket, config));
508 if (ct_command(sybase_sock->command, CS_LANG_CMD, querystr, CS_NULLTERM, CS_UNUSED) != CS_SUCCEED) {
509 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Unable to initiate command structure (ct_command())\n%s",
510 sql_error(sqlsocket, config));
514 if (ct_send(sybase_sock->command) != CS_SUCCEED) {
515 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Unable to send command (ct_send())\n%s",
516 sql_error(sqlsocket, config));
520 results_ret = ct_results(sybase_sock->command, &result_type);
522 switch (results_ret) {
526 switch (result_type) {
531 ** Houston, we have a row.
533 ** We set up a target buffer for the results data, and
534 ** associate the buffer with the results, but the actual
535 ** fetching takes place in sql_fetch_row. The layer above
536 ** MUST call sql_fetch_row and/or sql_finish_select_query
537 ** or this socket will be unusable and may cause segfaults
538 ** if reused later on.
542 ** Set up the DATAFMT structure that describes our target array
543 ** and tells sybase what we want future ct_fetch calls to do.
545 descriptor.datatype = CS_CHAR_TYPE; /* The target buffer is a string */
546 descriptor.format = CS_FMT_NULLTERM; /* Null termination please */
547 descriptor.maxlength = MAX_DATASTR_LEN; /* The string arrays are this large */
548 descriptor.count = 1; /* Fetch one row of data */
549 descriptor.locale = NULL; /* Don't do NLS stuff */
552 colcount = sql_num_fields(sqlsocket, config); /* Get number of elements in row result */
555 rowdata=(char **)rad_malloc(sizeof(char *) * (colcount+1)); /* Space for pointers */
556 memset(rowdata, 0, (sizeof(char *) * colcount+1)); /* NULL-pad the pointers */
558 for (i=0; i < colcount; i++) {
560 rowdata[i]=rad_malloc((MAX_DATASTR_LEN * sizeof(char))+1); /* Space to hold the result data */
562 /* Associate the target buffer with the data */
563 if (ct_bind(sybase_sock->command, i+1, &descriptor, rowdata[i], NULL, NULL) != CS_SUCCEED) {
564 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): ct_bind() failed)\n%s",
565 sql_error(sqlsocket, config));
570 rowdata[i]=NULL; /* Terminate the array */
571 sybase_sock->results=rowdata;
577 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Query returned no data");
582 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Unexpected result type from query\n%s",
583 sql_error(sqlsocket, config));
584 sql_finish_select_query(sqlsocket, config);
593 ** Serious failure, sybase requires us to cancel
594 ** the results and maybe even close the connection.
597 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Failure retrieving query results\n%s"
598 , sql_error(sqlsocket, config));
599 if ((ret = ct_cancel(NULL, sybase_sock->command, CS_CANCEL_ALL)) == CS_FAIL) {
600 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): cleaning up.");
601 ct_close(sybase_sock->connection, CS_FORCE_CLOSE);
602 sql_close(sqlsocket, config);
609 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Unexpected return value from ct_results()\n%s",
610 sql_error(sqlsocket, config));
618 /*************************************************************************
620 * Function: sql_store_result
622 * Purpose: database specific store_result function. Returns a result
625 *************************************************************************/
626 static int sql_store_result(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
628 ** Not needed for Sybase, code that may have gone here is
629 ** in sql_select_query and sql_fetch_row
635 /*************************************************************************
637 * Function: sql_num_fields
639 * Purpose: database specific num_fields function. Returns number
640 * of columns from query
642 *************************************************************************/
643 static int sql_num_fields(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
645 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
648 if (ct_res_info(sybase_sock->command, CS_NUMDATA, (CS_INT *)&num, CS_UNUSED, NULL) != CS_SUCCEED) {
649 radlog(L_ERR,"rlm_sql_sybase(sql_num_fields): error retrieving column count: %s",
650 sql_error(sqlsocket, config));
656 /*************************************************************************
658 * Function: sql_num_rows
660 * Purpose: database specific num_rows. Returns number of rows in
663 *************************************************************************/
664 static int sql_num_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
666 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
669 if (ct_res_info(sybase_sock->command, CS_ROW_COUNT, (CS_INT *)&num, CS_UNUSED, NULL) != CS_SUCCEED) {
670 radlog(L_ERR,"rlm_sql_sybase(sql_num_rows): error retrieving row count: %s",
671 sql_error(sqlsocket, config));
678 /*************************************************************************
680 * Function: sql_fetch_row
682 * Purpose: database specific fetch_row. Returns a SQL_ROW struct
683 * with all the data for the query in 'sqlsocket->row'. Returns
684 * 0 on success, -1 on failure, SQL_DOWN if 'database is down'.
686 *************************************************************************/
687 int sql_fetch_row(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
689 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
692 sqlsocket->row = NULL;
695 ret = ct_fetch(sybase_sock->command, CS_UNUSED, CS_UNUSED, CS_UNUSED, &count);
702 ** Serious failure, sybase requires us to cancel
703 ** the results and maybe even close the connection.
706 radlog(L_ERR,"rlm_sql_sybase(sql_fetch_row): Failure fething row data\n%s"
707 , sql_error(sqlsocket, config));
708 if ((ret = ct_cancel(NULL, sybase_sock->command, CS_CANCEL_ALL)) == CS_FAIL) {
709 radlog(L_ERR,"rlm_sql_sybase(sql_fetch_row): cleaning up.");
710 ct_close(sybase_sock->connection, CS_FORCE_CLOSE);
711 sql_close(sqlsocket, config);
723 sqlsocket->row = sybase_sock->results;
729 radlog(L_ERR,"rlm_sql_sybase(sql_fetch_row): Recoverable failure fething row data, try again perhaps?");
734 radlog(L_ERR,"rlm_sql_sybase(sql_fetch_row): Unexpected returncode from ct_fetch");
743 /*************************************************************************
745 * Function: sql_free_result
747 * Purpose: database specific free_result. Frees memory allocated
750 *************************************************************************/
751 static int sql_free_result(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
754 ** Not implemented, never called from rlm_sql anyway
755 ** result buffer is freed in the finish_query functions.
764 /*************************************************************************
766 * Function: sql_error
768 * Purpose: database specific error. Returns error associated with
771 *************************************************************************/
772 static char *sql_error(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
773 static char msg='\0';
775 static char msgbuf[2048];
777 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
783 char ctempbuf[2][512];
784 char stempbuf[2][512];
786 msgbuf[0]=(char)NULL;
787 ctempbuf[0][0]=(char)NULL;
788 ctempbuf[1][0]=(char)NULL;
789 stempbuf[0][0]=(char)NULL;
790 stempbuf[1][0]=(char)NULL;
792 if (ct_diag(sybase_sock->connection, CS_STATUS, CS_CLIENTMSG_TYPE, CS_UNUSED, &msgcount) != CS_SUCCEED) {
793 radlog(L_ERR,"rlm_sql_sybase(sql_error): Failed to get number of pending Client messages");
796 radlog(L_ERR,"rlm_sql_sybase(sql_error): Number of pending Client messages: %d", (int)msgcount);
798 for (i=1; i<=msgcount; i++) {
799 if (ct_diag(sybase_sock->connection, CS_GET, CS_CLIENTMSG_TYPE, (CS_INT)i, &cmsg) != CS_SUCCEED) {
800 radlog(L_ERR,"rlm_sql_sybase(sql_error): Failed to retrieve pending Client message");
803 sprintf(ctempbuf[i-1],"rlm_sql_sybase: Client Library Error: severity(%ld) number(%ld) origin(%ld) layer(%ld):\n%s",
804 (long)CS_SEVERITY(cmsg.severity),
805 (long)CS_NUMBER(cmsg.msgnumber),
806 (long)CS_ORIGIN(cmsg.msgnumber),
807 (long)CS_LAYER(cmsg.msgnumber),
812 if (ct_diag(sybase_sock->connection, CS_STATUS, CS_SERVERMSG_TYPE, CS_UNUSED, &msgcount) != CS_SUCCEED) {
813 radlog(L_ERR,"rlm_sql_sybase(sql_error): Failed to get number of pending Server messages");
816 radlog(L_ERR,"rlm_sql_sybase(sql_error): Number of pending Server messages: %d", (int)msgcount);
818 for (i=1; i<=msgcount; i++) {
819 if (ct_diag(sybase_sock->connection, CS_GET, CS_SERVERMSG_TYPE, (CS_INT)i, &smsg) != CS_SUCCEED) {
820 radlog(L_ERR,"rlm_sql_sybase(sql_error): Failed to retrieve pending Server message");
823 sprintf(stempbuf[i-1],"rlm_sql_sybase: Server message: severity(%ld) number(%ld) origin(%ld) layer(%ld):\n%s",
824 (long)CS_SEVERITY(cmsg.severity),
825 (long)CS_NUMBER(cmsg.msgnumber),
826 (long)CS_ORIGIN(cmsg.msgnumber),
827 (long)CS_LAYER(cmsg.msgnumber),
830 sprintf(msgbuf,"%s || %s || %s || %s", ctempbuf[1], ctempbuf[2], stempbuf[1], stempbuf[2]);
838 /*************************************************************************
840 * Function: sql_close
842 * Purpose: database specific close. Closes an open database
843 * connection and cleans up any open handles.
845 *************************************************************************/
846 static int sql_close(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
848 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
850 if (oracle_sock->conn) {
851 OCILogoff (oracle_sock->conn, oracle_sock->errHandle);
854 if (oracle_sock->queryHandle) {
855 OCIHandleFree((dvoid *)oracle_sock->queryHandle, (ub4) OCI_HTYPE_STMT);
857 if (oracle_sock->errHandle) {
858 OCIHandleFree((dvoid *)oracle_sock->errHandle, (ub4) OCI_HTYPE_ERROR);
860 if (oracle_sock->env) {
861 OCIHandleFree((dvoid *)oracle_sock->env, (ub4) OCI_HTYPE_ENV);
864 oracle_sock->conn = NULL;
870 /*************************************************************************
872 * Function: sql_finish_query
874 * Purpose: End the query, such as freeing memory
876 *************************************************************************/
877 static int sql_finish_query(SQLSOCK *sqlsocket, SQL_CONFIG *config)
879 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
881 ct_cancel(NULL, sybase_sock->command, CS_CANCEL_ALL);
883 if (ct_cmd_drop(sybase_sock->command) != CS_SUCCEED) {
884 radlog(L_ERR,"rlm_sql_sybase(sql_finish_query): Freeing command structure failed.");
893 /*************************************************************************
895 * Function: sql_finish_select_query
897 * Purpose: End the select query, such as freeing memory or result
899 *************************************************************************/
900 static int sql_finish_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
902 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
905 ct_cancel(NULL, sybase_sock->command, CS_CANCEL_ALL);
907 if (ct_cmd_drop(sybase_sock->command) != CS_SUCCEED) {
908 radlog(L_ERR,"rlm_sql_sybase(sql_finish_select_query): Freeing command structure failed.");
912 if (sybase_sock->results) {
913 while(sybase_sock->results[i]) free(sybase_sock->results[i++]);
914 free(sybase_sock->results);
915 sybase_sock->results=NULL;
923 /*************************************************************************
925 * Function: sql_affected_rows
927 * Purpose: Return the number of rows affected by the query (update,
930 *************************************************************************/
931 static int sql_affected_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
933 return sql_num_rows(sqlsocket, config);
940 /* Exported to rlm_sql */
941 rlm_sql_module_t rlm_sql_sybase = {
955 sql_finish_select_query,